All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.security.web.authentication.www.BasicAuthenticationFilter Maven / Gradle / Ivy

There is a newer version: 6.2.4
Show newest version
/*
 * Copyright 2004, 2005, 2006 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
 *
 *      https://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 org.springframework.security.web.authentication.www;

import java.io.IOException;
import java.nio.charset.Charset;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.log.LogMessage;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.NullRememberMeServices;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.util.Assert;
import org.springframework.web.filter.OncePerRequestFilter;

/**
 * Processes a HTTP request's BASIC authorization headers, putting the result into the
 * SecurityContextHolder.
 *
 * 

* For a detailed background on what this filter is designed to process, refer to * RFC 1945, Section 11.1. Any realm * name presented in the HTTP request is ignored. * *

* In summary, this filter is responsible for processing any request that has a HTTP * request header of Authorization with an authentication scheme of * Basic and a Base64-encoded username:password token. For * example, to authenticate user "Aladdin" with password "open sesame" the following * header would be presented: * *

 *
 * Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
 * 
* *

* This filter can be used to provide BASIC authentication services to both remoting * protocol clients (such as Hessian and SOAP) as well as standard user agents (such as * Internet Explorer and Netscape). *

* If authentication is successful, the resulting {@link Authentication} object will be * placed into the SecurityContextHolder. * *

* If authentication fails and ignoreFailure is false (the * default), an {@link AuthenticationEntryPoint} implementation is called (unless the * ignoreFailure property is set to true). Usually this should be * {@link BasicAuthenticationEntryPoint}, which will prompt the user to authenticate again * via BASIC authentication. * *

* Basic authentication is an attractive protocol because it is simple and widely * deployed. However, it still transmits a password in clear text and as such is * undesirable in many situations. Digest authentication is also provided by Spring * Security and should be used instead of Basic authentication wherever possible. See * {@link org.springframework.security.web.authentication.www.DigestAuthenticationFilter}. *

* Note that if a {@link RememberMeServices} is set, this filter will automatically send * back remember-me details to the client. Therefore, subsequent requests will not need to * present a BASIC authentication header as they will be authenticated using the * remember-me mechanism. * * @author Ben Alex */ public class BasicAuthenticationFilter extends OncePerRequestFilter { private AuthenticationEntryPoint authenticationEntryPoint; private AuthenticationManager authenticationManager; private RememberMeServices rememberMeServices = new NullRememberMeServices(); private boolean ignoreFailure = false; private String credentialsCharset = "UTF-8"; private BasicAuthenticationConverter authenticationConverter = new BasicAuthenticationConverter(); /** * Creates an instance which will authenticate against the supplied * {@code AuthenticationManager} and which will ignore failed authentication attempts, * allowing the request to proceed down the filter chain. * @param authenticationManager the bean to submit authentication requests to */ public BasicAuthenticationFilter(AuthenticationManager authenticationManager) { Assert.notNull(authenticationManager, "authenticationManager cannot be null"); this.authenticationManager = authenticationManager; this.ignoreFailure = true; } /** * Creates an instance which will authenticate against the supplied * {@code AuthenticationManager} and use the supplied {@code AuthenticationEntryPoint} * to handle authentication failures. * @param authenticationManager the bean to submit authentication requests to * @param authenticationEntryPoint will be invoked when authentication fails. * Typically an instance of {@link BasicAuthenticationEntryPoint}. */ public BasicAuthenticationFilter(AuthenticationManager authenticationManager, AuthenticationEntryPoint authenticationEntryPoint) { Assert.notNull(authenticationManager, "authenticationManager cannot be null"); Assert.notNull(authenticationEntryPoint, "authenticationEntryPoint cannot be null"); this.authenticationManager = authenticationManager; this.authenticationEntryPoint = authenticationEntryPoint; } @Override public void afterPropertiesSet() { Assert.notNull(this.authenticationManager, "An AuthenticationManager is required"); if (!isIgnoreFailure()) { Assert.notNull(this.authenticationEntryPoint, "An AuthenticationEntryPoint is required"); } } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { try { UsernamePasswordAuthenticationToken authRequest = this.authenticationConverter.convert(request); if (authRequest == null) { this.logger.trace("Did not process authentication request since failed to find " + "username and password in Basic Authorization header"); chain.doFilter(request, response); return; } String username = authRequest.getName(); this.logger.trace(LogMessage.format("Found username '%s' in Basic Authorization header", username)); if (authenticationIsRequired(username)) { Authentication authResult = this.authenticationManager.authenticate(authRequest); SecurityContextHolder.getContext().setAuthentication(authResult); if (this.logger.isDebugEnabled()) { this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult)); } this.rememberMeServices.loginSuccess(request, response, authResult); onSuccessfulAuthentication(request, response, authResult); } } catch (AuthenticationException ex) { SecurityContextHolder.clearContext(); this.logger.debug("Failed to process authentication request", ex); this.rememberMeServices.loginFail(request, response); onUnsuccessfulAuthentication(request, response, ex); if (this.ignoreFailure) { chain.doFilter(request, response); } else { this.authenticationEntryPoint.commence(request, response, ex); } return; } chain.doFilter(request, response); } private boolean authenticationIsRequired(String username) { // Only reauthenticate if username doesn't match SecurityContextHolder and user // isn't authenticated (see SEC-53) Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication(); if (existingAuth == null || !existingAuth.isAuthenticated()) { return true; } // Limit username comparison to providers which use usernames (ie // UsernamePasswordAuthenticationToken) (see SEC-348) if (existingAuth instanceof UsernamePasswordAuthenticationToken && !existingAuth.getName().equals(username)) { return true; } // Handle unusual condition where an AnonymousAuthenticationToken is already // present. This shouldn't happen very often, as BasicProcessingFitler is meant to // be earlier in the filter chain than AnonymousAuthenticationFilter. // Nevertheless, presence of both an AnonymousAuthenticationToken together with a // BASIC authentication request header should indicate reauthentication using the // BASIC protocol is desirable. This behaviour is also consistent with that // provided by form and digest, both of which force re-authentication if the // respective header is detected (and in doing so replace/ any existing // AnonymousAuthenticationToken). See SEC-610. return (existingAuth instanceof AnonymousAuthenticationToken); } protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException { } protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException { } protected AuthenticationEntryPoint getAuthenticationEntryPoint() { return this.authenticationEntryPoint; } protected AuthenticationManager getAuthenticationManager() { return this.authenticationManager; } protected boolean isIgnoreFailure() { return this.ignoreFailure; } public void setAuthenticationDetailsSource( AuthenticationDetailsSource authenticationDetailsSource) { this.authenticationConverter.setAuthenticationDetailsSource(authenticationDetailsSource); } public void setRememberMeServices(RememberMeServices rememberMeServices) { Assert.notNull(rememberMeServices, "rememberMeServices cannot be null"); this.rememberMeServices = rememberMeServices; } public void setCredentialsCharset(String credentialsCharset) { Assert.hasText(credentialsCharset, "credentialsCharset cannot be null or empty"); this.credentialsCharset = credentialsCharset; this.authenticationConverter.setCredentialsCharset(Charset.forName(credentialsCharset)); } protected String getCredentialsCharset(HttpServletRequest httpRequest) { return this.credentialsCharset; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy