aspectj
aspectjrt
diff --git a/sandbox/src/main/java/org/acegisecurity/providers/smb/AbstractSmbAuthenticationProvider.java b/sandbox/src/main/java/org/acegisecurity/providers/smb/AbstractSmbAuthenticationProvider.java
new file mode 100644
index 0000000000..7c8d1866a9
--- /dev/null
+++ b/sandbox/src/main/java/org/acegisecurity/providers/smb/AbstractSmbAuthenticationProvider.java
@@ -0,0 +1,121 @@
+/* Copyright 2004, 2005 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers.smb;
+
+import jcifs.UniAddress;
+
+import jcifs.smb.NtlmPasswordAuthentication;
+import jcifs.smb.SmbAuthException;
+import jcifs.smb.SmbException;
+import jcifs.smb.SmbSession;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.AuthenticationException;
+import net.sf.acegisecurity.AuthenticationServiceException;
+import net.sf.acegisecurity.BadCredentialsException;
+import net.sf.acegisecurity.providers.AuthenticationProvider;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * An {@link AuthenticationProvider} implementation that relies on jcifs in order to provide an authentication
+ * service on a Windows network. This implementation relies on a {@link
+ * #setAuthorizationProvider(AuthenticationProvider) delegate provider} in
+ * order for authorization information to be filled into the authorized {@link
+ * Authentication token}. Subclasses must implement the logic that {@link
+ * #getNtlmPasswordAuthentication(Authentication) extracts the jcifs }{@link
+ * NtlmPasswordAuthentication } object from the particular {@link
+ * Authentication } token implementation and the one that {@link
+ * #getDomainController(Authentication, NtlmPasswordAuthentication) extracts
+ * the domain controller address }.
+ *
+ * @author Davide Baroncelli
+ * @version $Id$
+ */
+public abstract class AbstractSmbAuthenticationProvider
+ implements AuthenticationProvider {
+ //~ Instance fields ========================================================
+
+ private AuthenticationProvider authorizationProvider;
+ private Log log = LogFactory.getLog(this.getClass());
+
+ //~ Methods ================================================================
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param authorizationProvider The {@link AuthenticationProvider } which
+ * will be contacted in order for it to fill authorization info in
+ * the (already authenticated) {@link Authentication } object that
+ * they will be passed.
+ */
+ public void setAuthorizationProvider(
+ AuthenticationProvider authorizationProvider) {
+ this.authorizationProvider = authorizationProvider;
+ }
+
+ public Authentication authenticate(Authentication authentication)
+ throws AuthenticationException {
+ NtlmPasswordAuthentication ntlm = getNtlmPasswordAuthentication(authentication);
+ UniAddress dc = getDomainController(authentication, ntlm);
+
+ return performAuthentication(dc, ntlm, authentication);
+ }
+
+ protected abstract UniAddress getDomainController(
+ Authentication authentication,
+ NtlmPasswordAuthentication ntlmAuthentication);
+
+ protected abstract NtlmPasswordAuthentication getNtlmPasswordAuthentication(
+ Authentication authentication);
+
+ protected Authentication performAuthentication(UniAddress dc,
+ NtlmPasswordAuthentication ntlm, Authentication authentication) {
+ try {
+ // this performs authentication...
+ SmbSession.logon(dc, ntlm);
+
+ if (log.isDebugEnabled()) {
+ log.debug(ntlm + " successfully authenticated against " + dc);
+ }
+
+ // ...and this performs authorization.
+ Authentication authorizedResult = authorizationProvider
+ .authenticate(authentication);
+
+ return authorizedResult;
+ } catch (SmbException se) {
+ log.error(ntlm.getName() + ": 0x"
+ + jcifs.util.Hexdump.toHexString(se.getNtStatus(), 8) + ": "
+ + se);
+
+ if (se instanceof SmbAuthException) {
+ SmbAuthException sae = (SmbAuthException) se;
+
+ if (se.getNtStatus() == SmbAuthException.NT_STATUS_ACCESS_VIOLATION) {
+ throw new ChallengeExpiredException(sae.getMessage(), sae);
+ } else {
+ throw new BadCredentialsException(sae.getMessage(), sae);
+ }
+ } else {
+ throw new AuthenticationServiceException(se.getMessage(), se);
+ }
+ }
+ }
+}
diff --git a/sandbox/src/main/java/org/acegisecurity/providers/smb/ChallengeExpiredException.java b/sandbox/src/main/java/org/acegisecurity/providers/smb/ChallengeExpiredException.java
new file mode 100644
index 0000000000..698c8cac11
--- /dev/null
+++ b/sandbox/src/main/java/org/acegisecurity/providers/smb/ChallengeExpiredException.java
@@ -0,0 +1,37 @@
+/* Copyright 2004, 2005 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers.smb;
+
+import net.sf.acegisecurity.AuthenticationException;
+
+
+/**
+ * Thrown if
+ *
+ * @author Davide Baroncelli
+ * @version $Id$
+ */
+public class ChallengeExpiredException extends AuthenticationException {
+ //~ Constructors ===========================================================
+
+ public ChallengeExpiredException(String msg) {
+ super(msg);
+ }
+
+ public ChallengeExpiredException(String msg, Throwable t) {
+ super(msg, t);
+ }
+}
diff --git a/sandbox/src/main/java/org/acegisecurity/providers/smb/NtlmAuthenticationToken.java b/sandbox/src/main/java/org/acegisecurity/providers/smb/NtlmAuthenticationToken.java
new file mode 100644
index 0000000000..a5721ca6a9
--- /dev/null
+++ b/sandbox/src/main/java/org/acegisecurity/providers/smb/NtlmAuthenticationToken.java
@@ -0,0 +1,86 @@
+/* Copyright 2004, 2005 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers.smb;
+
+import jcifs.UniAddress;
+
+import jcifs.smb.NtlmPasswordAuthentication;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.providers.AbstractAuthenticationToken;
+
+
+/**
+ * {@link Authentication } implementation for NTLM smb authentication.
+ *
+ * @author Davide Baroncelli
+ * @version $Id$
+ *
+ * @see net.sf.acegisecurity.ui.ntlm.NtlmProcessingFilter
+ * @see net.sf.acegisecurity.providers.smb.SmbNtlmAuthenticationProvider
+ */
+public class NtlmAuthenticationToken extends AbstractAuthenticationToken {
+ //~ Instance fields ========================================================
+
+ private NtlmPasswordAuthentication ntlmPasswordAuthentication;
+ private transient UniAddress domainController;
+ private GrantedAuthority[] authorities;
+ private boolean authenticated;
+
+ //~ Constructors ===========================================================
+
+ public NtlmAuthenticationToken(
+ NtlmPasswordAuthentication ntlmPasswordAuthentication,
+ UniAddress domainController) {
+ this.ntlmPasswordAuthentication = ntlmPasswordAuthentication;
+ this.domainController = domainController;
+ }
+
+ //~ Methods ================================================================
+
+ public void setAuthenticated(boolean isAuthenticated) {
+ this.authenticated = isAuthenticated;
+ }
+
+ public boolean isAuthenticated() {
+ return authenticated;
+ }
+
+ public void setAuthorities(GrantedAuthority[] authorities) {
+ this.authorities = authorities;
+ }
+
+ public GrantedAuthority[] getAuthorities() {
+ return authorities;
+ }
+
+ public Object getCredentials() {
+ return ntlmPasswordAuthentication.getPassword();
+ }
+
+ public UniAddress getDomainController() {
+ return domainController;
+ }
+
+ public NtlmPasswordAuthentication getNtlmPasswordAuthentication() {
+ return ntlmPasswordAuthentication;
+ }
+
+ public Object getPrincipal() {
+ return ntlmPasswordAuthentication.getUsername();
+ }
+}
diff --git a/sandbox/src/main/java/org/acegisecurity/providers/smb/SmbBasicAuthenticationProvider.java b/sandbox/src/main/java/org/acegisecurity/providers/smb/SmbBasicAuthenticationProvider.java
new file mode 100644
index 0000000000..77adc25c70
--- /dev/null
+++ b/sandbox/src/main/java/org/acegisecurity/providers/smb/SmbBasicAuthenticationProvider.java
@@ -0,0 +1,97 @@
+/* Copyright 2004, 2005 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers.smb;
+
+import jcifs.Config;
+import jcifs.UniAddress;
+
+import jcifs.smb.NtlmPasswordAuthentication;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.BadCredentialsException;
+import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+
+import java.net.UnknownHostException;
+
+
+/**
+ * Provides authentication of a basic {@link
+ * UsernamePasswordAuthenticationToken } on a ntlm domain via smb/cifs.
+ *
+ * @author Davide Baroncelli
+ * @version $Id$
+ */
+public class SmbBasicAuthenticationProvider
+ extends AbstractSmbAuthenticationProvider {
+ //~ Instance fields ========================================================
+
+ String domainController;
+
+ //~ Methods ================================================================
+
+ public void setDomainController(String domainController) {
+ this.domainController = domainController;
+ }
+
+ public boolean supports(Class authentication) {
+ return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
+ }
+
+ protected UniAddress getDomainController(Authentication authentication,
+ NtlmPasswordAuthentication ntlmAuthentication) {
+ try {
+ if (domainController == null) {
+ domainController = Config.getProperty("jcifs.smb.client.domain");
+ }
+
+ String domain = domainController;
+
+ if (domain == null) {
+ domain = ntlmAuthentication.getDomain();
+ }
+
+ UniAddress dc = UniAddress.getByName(domain, true);
+
+ return dc;
+ } catch (UnknownHostException uhe) {
+ throw new BadCredentialsException(
+ "no host could be found for the name "
+ + ntlmAuthentication.getDomain(), uhe);
+ }
+ }
+
+ protected NtlmPasswordAuthentication getNtlmPasswordAuthentication(
+ Authentication authentication) {
+ UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
+ String username = token.getPrincipal().toString();
+ String password = (String) token.getCredentials();
+ int index = username.indexOf('\\');
+
+ if (index == -1) {
+ index = username.indexOf('/');
+ }
+
+ // if domain is null then the jcifs default is used
+ // (this is set through the "jcifs.smb.client.domain" Config property)
+ String domain = (index != -1) ? username.substring(0, index) : null;
+ username = (index != -1) ? username.substring(index + 1) : username;
+
+ NtlmPasswordAuthentication ntlm = new NtlmPasswordAuthentication(domain,
+ username, password);
+
+ return ntlm;
+ }
+}
diff --git a/sandbox/src/main/java/org/acegisecurity/providers/smb/SmbNtlmAuthenticationProvider.java b/sandbox/src/main/java/org/acegisecurity/providers/smb/SmbNtlmAuthenticationProvider.java
new file mode 100644
index 0000000000..077794ab27
--- /dev/null
+++ b/sandbox/src/main/java/org/acegisecurity/providers/smb/SmbNtlmAuthenticationProvider.java
@@ -0,0 +1,60 @@
+/* Copyright 2004, 2005 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers.smb;
+
+import jcifs.UniAddress;
+
+import jcifs.smb.NtlmPasswordAuthentication;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.ui.ntlm.NtlmProcessingFilter;
+
+
+/**
+ * This class provides authentication through smb of {@link
+ * NtlmAuthenticationToken } (i.e. tokens obtained through the NTLM
+ * Authorization method by {@link NtlmProcessingFilter } ).
+ *
+ * @author Davide Baroncelli
+ * @version $Id$
+ *
+ * @see net.sf.acegisecurity.ui.ntlm.NtlmProcessingFilter
+ */
+public class SmbNtlmAuthenticationProvider
+ extends AbstractSmbAuthenticationProvider {
+ //~ Methods ================================================================
+
+ public boolean supports(Class authentication) {
+ return NtlmAuthenticationToken.class.isAssignableFrom(authentication);
+ }
+
+ protected UniAddress getDomainController(Authentication authentication,
+ NtlmPasswordAuthentication ntlmAuthentication) {
+ NtlmAuthenticationToken ntlmToken = (NtlmAuthenticationToken) authentication;
+ UniAddress dc = ntlmToken.getDomainController();
+
+ return dc;
+ }
+
+ protected NtlmPasswordAuthentication getNtlmPasswordAuthentication(
+ Authentication authentication) {
+ NtlmAuthenticationToken ntlmToken = (NtlmAuthenticationToken) authentication;
+ NtlmPasswordAuthentication ntlm = ntlmToken
+ .getNtlmPasswordAuthentication();
+
+ return ntlm;
+ }
+}
diff --git a/sandbox/src/main/java/org/acegisecurity/ui/ntlm/NtlmProcessingFilter.java b/sandbox/src/main/java/org/acegisecurity/ui/ntlm/NtlmProcessingFilter.java
new file mode 100644
index 0000000000..41b3c99d4f
--- /dev/null
+++ b/sandbox/src/main/java/org/acegisecurity/ui/ntlm/NtlmProcessingFilter.java
@@ -0,0 +1,287 @@
+/*
+ * LICENSE IS UNKNOWN (SEE TODO COMMENT LATER IN SOURCE CODE)
+ */
+package net.sf.acegisecurity.ui.ntlm;
+
+import jcifs.Config;
+import jcifs.UniAddress;
+
+import jcifs.http.NtlmSsp;
+
+import jcifs.smb.NtlmChallenge;
+import jcifs.smb.NtlmPasswordAuthentication;
+import jcifs.smb.SmbSession;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.AuthenticationException;
+import net.sf.acegisecurity.AuthenticationManager;
+import net.sf.acegisecurity.BadCredentialsException;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint;
+import net.sf.acegisecurity.providers.smb.NtlmAuthenticationToken;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.factory.InitializingBean;
+
+import org.springframework.util.Assert;
+
+import java.io.IOException;
+
+import java.util.Iterator;
+import java.util.Properties;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+
+/**
+ * A reimplementation of the jcifs NtlmHttpFilter suitable for use with the
+ * Acegi Security System.
+ *
+ *
+ * This servlet Filter can be used to negotiate password hashes with MSIE
+ * clients using NTLM SSP. This is similar to Authentication:
+ * BASIC
but weakly encrypted and without requiring the user to
+ * re-supply authentication credentials.
+ *
+ *
+ * @author Davide Baroncelli
+ * @version $Id$
+ */
+public class NtlmProcessingFilter implements Filter, InitializingBean {
+ //~ Static fields/initializers =============================================
+
+ private static final String CHALLENGE_ATTR_NAME = "NtlmHttpChal";
+
+ //~ Instance fields ========================================================
+
+ private AuthenticationEntryPoint authenticationEntryPoint;
+ private AuthenticationManager authenticationManager;
+
+ // TODO: Verify licensing, as original contributor reported that large parts of this code where taken from jCifs NtmlHttpFilter: can this be re-licensed to APL (?).
+ private Log log = LogFactory.getLog(this.getClass());
+ private String defaultDomain;
+ private String domainController;
+ private boolean loadBalance;
+
+ //~ Methods ================================================================
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param authenticationEntryPoint The entry point that will be called if
+ * the "transparent" authentication fails for some reason: don't
+ * use the same {@link NtlmProcessingFilterEntryPoint} that is used
+ * in order to commence the NTLM authentication or the user's
+ * browser would probably loop
+ */
+ public void setAuthenticationEntryPoint(
+ AuthenticationEntryPoint authenticationEntryPoint) {
+ this.authenticationEntryPoint = authenticationEntryPoint;
+ }
+
+ public void setAuthenticationManager(
+ AuthenticationManager authenticationManager) {
+ this.authenticationManager = authenticationManager;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param defaultDomain The domain that will be specified as part of the
+ * authentication credentials if not specified by the username.
+ */
+ public void setDefaultDomain(String defaultDomain) {
+ this.defaultDomain = defaultDomain;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param domainController The domain controller address: if not set the
+ * default domain is used.
+ */
+ public void setDomainController(String domainController) {
+ this.domainController = domainController;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param properties A {@link Properties} object whose properties with
+ * names starting with "jcifs." will be set into the jCifs {@link
+ * Config}.
+ */
+ public void setJCifsProperties(Properties properties) {
+ for (Iterator iterator = properties.keySet().iterator();
+ iterator.hasNext();) {
+ String propertyName = (String) iterator.next();
+ String propertyValue = properties.getProperty(propertyName);
+
+ if (propertyName.startsWith("jcifs.")) {
+ if (log.isInfoEnabled()) {
+ log.info("setting jcifs property " + propertyName + ":"
+ + propertyValue);
+ }
+
+ Config.setProperty(propertyName, propertyValue);
+ } else {
+ if (log.isInfoEnabled()) {
+ log.info("ignoring non-jcifs property " + propertyName
+ + ":" + propertyValue);
+ }
+ }
+ }
+ }
+
+ public void setLoadBalance(boolean loadBalance) {
+ this.loadBalance = loadBalance;
+ }
+
+ public void afterPropertiesSet() throws Exception {
+ // Set jcifs properties we know we want; soTimeout and cachePolicy to 10min
+ Config.setProperty("jcifs.smb.client.soTimeout", "300000");
+ Config.setProperty("jcifs.netbios.cachePolicy", "1200");
+
+ if (domainController == null) {
+ domainController = defaultDomain;
+ }
+
+ if (defaultDomain != null) {
+ Config.setProperty("jcifs.smb.client.domain", defaultDomain);
+ }
+
+ Assert.notNull(authenticationEntryPoint,
+ "The authenticationEntryPoint property must be set before "
+ + "NtlmProcessingFilter bean initialization");
+ Assert.notNull(authenticationManager,
+ "The authenticationManager property must be set before "
+ + "NtlmProcessingFilter bean initialization");
+ }
+
+ public void destroy() {}
+
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+ NtlmPasswordAuthentication ntlm = null;
+ HttpServletRequest req = (HttpServletRequest) request;
+ HttpServletResponse resp = (HttpServletResponse) response;
+
+ try {
+ String msg = req.getHeader("Authorization");
+
+ UniAddress dc = null;
+
+ // the "basic" authentication case (both secure + insecure) originally in jcifs NtlmFilter has been
+ // refactored out, in order for it to be supported by the acegi BasicProcessingFilter +
+ // SmbNtlmAuthenticationProvider ( + SecureChannelProcessor) combination */
+ if ((msg != null) && (msg.startsWith("NTLM "))) {
+ if (log.isDebugEnabled()) {
+ log.debug("NTLM Authorization header received");
+ }
+
+ HttpSession ssn = req.getSession();
+ byte[] challenge;
+
+ if (loadBalance) {
+ NtlmChallenge chal = (NtlmChallenge) ssn.getAttribute(CHALLENGE_ATTR_NAME);
+
+ if (chal == null) {
+ chal = SmbSession.getChallengeForDomain();
+
+ if (log.isDebugEnabled()) {
+ log.debug(
+ "got load balanced challenge for domain: "
+ + chal);
+ }
+
+ ssn.setAttribute(CHALLENGE_ATTR_NAME, chal);
+ }
+
+ dc = chal.dc;
+ challenge = chal.challenge;
+ } else {
+ // no challenge in session, here: the server itself keeps the challenge alive for a certain time
+ dc = UniAddress.getByName(domainController, true);
+ challenge = SmbSession.getChallenge(dc);
+
+ if (log.isDebugEnabled()) {
+ log.debug("domain controller is " + dc
+ + ", challenge is " + challenge);
+ }
+ }
+
+ ntlm = NtlmSsp.authenticate(req, resp, challenge);
+
+ if (ntlm == null) {
+ if (log.isDebugEnabled()) {
+ log.debug(
+ "null ntlm authentication results: sending challenge to browser");
+ }
+
+ return; // this means we must send the challenge to the browser
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("ntlm negotiation complete");
+ }
+
+ ssn.removeAttribute(CHALLENGE_ATTR_NAME); /* negotiation complete, remove the challenge object */
+ }
+
+ NtlmAuthenticationToken ntlmToken = newNtlmAuthenticationToken(ntlm,
+ dc);
+ Authentication authResult = authenticationManager.authenticate(ntlmToken);
+
+ if (log.isDebugEnabled()) {
+ log.debug("ntlm token authenticated ");
+ }
+
+ successfulAuthentication(req, resp, authResult);
+ }
+ } catch (AuthenticationException ae) {
+ unsuccessfulAuthentication(req, resp, ntlm, ae);
+
+ return;
+ }
+
+ chain.doFilter(request, response);
+ }
+
+ public void init(FilterConfig filterConfig) throws ServletException {}
+
+ protected NtlmAuthenticationToken newNtlmAuthenticationToken(
+ NtlmPasswordAuthentication ntlm, UniAddress dc) {
+ return new NtlmAuthenticationToken(ntlm, dc);
+ }
+
+ protected void successfulAuthentication(HttpServletRequest request,
+ HttpServletResponse response, Authentication authResult) {
+ if (log.isDebugEnabled()) {
+ log.debug("Authentication success: " + authResult.toString());
+ }
+
+ SecurityContextHolder.getContext().setAuthentication(authResult);
+ }
+
+ protected void unsuccessfulAuthentication(HttpServletRequest req,
+ HttpServletResponse resp, NtlmPasswordAuthentication ntlm,
+ AuthenticationException ae) throws IOException, ServletException {
+ if (log.isDebugEnabled()) {
+ log.debug("Authentication request for user: " + ntlm.getUsername()
+ + " failed: " + ae.toString());
+ }
+
+ SecurityContextHolder.getContext().setAuthentication(null);
+ authenticationEntryPoint.commence(req, resp,
+ new BadCredentialsException(ae.getMessage(), ae));
+ }
+}
diff --git a/sandbox/src/main/java/org/acegisecurity/ui/ntlm/NtlmProcessingFilterEntryPoint.java b/sandbox/src/main/java/org/acegisecurity/ui/ntlm/NtlmProcessingFilterEntryPoint.java
new file mode 100644
index 0000000000..20baa26792
--- /dev/null
+++ b/sandbox/src/main/java/org/acegisecurity/ui/ntlm/NtlmProcessingFilterEntryPoint.java
@@ -0,0 +1,47 @@
+/* Copyright 2004, 2005 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.ui.ntlm;
+
+import net.sf.acegisecurity.AuthenticationException;
+import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * An entry point for the NTLM authentication process.
+ *
+ * @author Davide Baroncelli
+ * @version $Id$
+ */
+public class NtlmProcessingFilterEntryPoint implements AuthenticationEntryPoint {
+ //~ Methods ================================================================
+
+ public void commence(ServletRequest request, ServletResponse response,
+ AuthenticationException authException)
+ throws IOException, ServletException {
+ HttpServletResponse resp = (HttpServletResponse) response;
+ resp.setHeader("WWW-Authenticate", "NTLM");
+ resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ resp.sendError(HttpServletResponse.SC_UNAUTHORIZED,
+ (authException != null) ? authException.getMessage() : "");
+ }
+}