Merge PR #5
- Fixing merge conflicts - Tidy up and polish - Changed KerberosTicketValidation to be transient in KerberosServiceRequestToken because we get NotSerializableException for SPRING_SECURITY_CONTEXT. Not really sure if that is ever needed in sec context. - Added simple RestTemplate test to see that this doesn't break anything, should somehow to come up with a test verify some WinRM functionality.
This commit is contained in:
@@ -137,6 +137,37 @@ public class KerberosRestTemplateTests extends KerberosSecurityTestcase {
|
||||
assertThat(response, is("login"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpnegoWithSuccessHandler() throws Exception {
|
||||
|
||||
MiniKdc kdc = getKdc();
|
||||
File workDir = getWorkDir();
|
||||
String host = InetAddress.getLocalHost().getCanonicalHostName();
|
||||
|
||||
String serverPrincipal = "HTTP/" + host;
|
||||
File serverKeytab = new File(workDir, "server.keytab");
|
||||
kdc.createPrincipal(serverKeytab, serverPrincipal);
|
||||
|
||||
String clientPrincipal = "client/" + host;
|
||||
File clientKeytab = new File(workDir, "client.keytab");
|
||||
kdc.createPrincipal(clientKeytab, clientPrincipal);
|
||||
|
||||
|
||||
context = SpringApplication.run(new Object[] { WebSecurityConfigSuccessHandler.class, VanillaWebConfiguration.class,
|
||||
WebConfiguration.class }, new String[] { "--security.basic.enabled=true",
|
||||
"--security.user.name=username", "--security.user.password=password",
|
||||
"--serverPrincipal=" + serverPrincipal, "--serverKeytab=" + serverKeytab.getAbsolutePath() });
|
||||
|
||||
PortInitListener portInitListener = context.getBean(PortInitListener.class);
|
||||
assertThat(portInitListener.latch.await(10, TimeUnit.SECONDS), is(true));
|
||||
int port = portInitListener.port;
|
||||
|
||||
KerberosRestTemplate restTemplate = new KerberosRestTemplate(clientKeytab.getAbsolutePath(), clientPrincipal);
|
||||
|
||||
String response = restTemplate.getForObject("http://" + host + ":" + port + "/hello", String.class);
|
||||
assertThat(response, is("home"));
|
||||
}
|
||||
|
||||
protected static class PortInitListener implements ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
|
||||
public int port;
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.security.extensions.kerberos.client;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.extensions.kerberos.KerberosServiceAuthenticationProvider;
|
||||
import org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator;
|
||||
import org.springframework.security.extensions.kerberos.web.ResponseHeaderSettingKerberosAuthenticationSuccessHandler;
|
||||
import org.springframework.security.extensions.kerberos.web.SpnegoAuthenticationProcessingFilter;
|
||||
import org.springframework.security.extensions.kerberos.web.SpnegoEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvcSecurity
|
||||
public class WebSecurityConfigSuccessHandler extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Value("${serverPrincipal}")
|
||||
private String serverPrincipal;
|
||||
|
||||
@Value("${serverKeytab}")
|
||||
private String serverKeytab;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.exceptionHandling().authenticationEntryPoint(spnegoEntryPoint()).and()
|
||||
.authorizeRequests()
|
||||
.antMatchers("/", "/home").permitAll()
|
||||
.antMatchers("/hello").access("hasRole('ROLE_USER')")
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
|
||||
.addFilterBefore(spnegoAuthenticationProcessingFilter(authenticationManagerBean()), BasicAuthenticationFilter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.authenticationProvider(kerberosServiceAuthenticationProvider());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SpnegoEntryPoint spnegoEntryPoint() {
|
||||
return new SpnegoEntryPoint();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(
|
||||
AuthenticationManager authenticationManager) {
|
||||
SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();
|
||||
|
||||
ResponseHeaderSettingKerberosAuthenticationSuccessHandler successHandler = new ResponseHeaderSettingKerberosAuthenticationSuccessHandler();
|
||||
filter.setSuccessHandler(successHandler);
|
||||
|
||||
filter.setAuthenticationManager(authenticationManager);
|
||||
return filter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() {
|
||||
KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
|
||||
provider.setTicketValidator(sunJaasKerberosTicketValidator());
|
||||
provider.setUserDetailsService(dummyUserDetailsService());
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() {
|
||||
SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
|
||||
ticketValidator.setServicePrincipal(serverPrincipal);
|
||||
ticketValidator.setKeyTabLocation(new FileSystemResource(serverKeytab));
|
||||
ticketValidator.setDebug(true);
|
||||
return ticketValidator;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DummyUserDetailsService dummyUserDetailsService() {
|
||||
return new DummyUserDetailsService();
|
||||
}
|
||||
|
||||
static class DummyUserDetailsService implements UserDetailsService {
|
||||
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
return new User(username, "notUsed", true, true, true, true,
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsChecker;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.extensions.kerberos.KerberosTicketValidator.KerberosTicketValidation;
|
||||
import org.springframework.security.extensions.kerberos.web.SpnegoAuthenticationProcessingFilter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -42,6 +43,7 @@ import org.springframework.util.Assert;
|
||||
* You can see an example configuration in <code>SpnegoAuthenticationProcessingFilter</code>.
|
||||
*
|
||||
* @author Mike Wiesner
|
||||
* @author Jeremy Stone
|
||||
* @since 1.0
|
||||
* @see KerberosTicketValidator
|
||||
* @see UserDetailsService
|
||||
@@ -56,36 +58,22 @@ public class KerberosServiceAuthenticationProvider implements
|
||||
private UserDetailsService userDetailsService;
|
||||
private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
|
||||
|
||||
|
||||
/** The <code>UserDetailsService</code> to use, for loading the user properties
|
||||
* and the <code>GrantedAuthorities</code>.
|
||||
*/
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
/** The <code>KerberosTicketValidator</code> to use, for validating
|
||||
* the Kerberos/SPNEGO tickets.
|
||||
*/
|
||||
public void setTicketValidator(KerberosTicketValidator ticketValidator) {
|
||||
this.ticketValidator = ticketValidator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
KerberosServiceRequestToken auth = (KerberosServiceRequestToken) authentication;
|
||||
byte[] token = auth.getToken();
|
||||
LOG.debug("Try to validate Kerberos Token");
|
||||
String username = this.ticketValidator.validateTicket(token);
|
||||
LOG.debug("Succesfully validated " + username);
|
||||
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
|
||||
KerberosTicketValidation ticketValidation = this.ticketValidator.validateTicket(token);
|
||||
LOG.debug("Succesfully validated " + ticketValidation.username());
|
||||
UserDetails userDetails = this.userDetailsService.loadUserByUsername(ticketValidation.username());
|
||||
userDetailsChecker.check(userDetails);
|
||||
additionalAuthenticationChecks(userDetails, auth);
|
||||
KerberosServiceRequestToken responseAuth = new KerberosServiceRequestToken(userDetails, userDetails.getAuthorities(), token);
|
||||
KerberosServiceRequestToken responseAuth = new KerberosServiceRequestToken(
|
||||
userDetails, ticketValidation,
|
||||
userDetails.getAuthorities(), token);
|
||||
responseAuth.setDetails(authentication.getDetails());
|
||||
return responseAuth;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -99,6 +87,26 @@ public class KerberosServiceAuthenticationProvider implements
|
||||
Assert.notNull(this.userDetailsService, "userDetailsService must be specified");
|
||||
}
|
||||
|
||||
/**
|
||||
* The <code>UserDetailsService</code> to use, for loading the user properties
|
||||
* and the <code>GrantedAuthorities</code>.
|
||||
*
|
||||
* @param userDetailsService the new user details service
|
||||
*/
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
/**
|
||||
* The <code>KerberosTicketValidator</code> to use, for validating
|
||||
* the Kerberos/SPNEGO tickets.
|
||||
*
|
||||
* @param ticketValidator the new ticket validator
|
||||
*/
|
||||
public void setTicketValidator(KerberosTicketValidator ticketValidator) {
|
||||
this.ticketValidator = ticketValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows subclasses to perform any additional checks of a returned <code>UserDetails</code>
|
||||
* for a given authentication request.
|
||||
@@ -110,7 +118,6 @@ public class KerberosServiceAuthenticationProvider implements
|
||||
*/
|
||||
protected void additionalAuthenticationChecks(UserDetails userDetails, KerberosServiceRequestToken authentication)
|
||||
throws AuthenticationException {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,50 +15,70 @@
|
||||
*/
|
||||
package org.springframework.security.extensions.kerberos;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import org.ietf.jgss.GSSContext;
|
||||
import org.ietf.jgss.MessageProp;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.crypto.codec.Base64;
|
||||
import org.springframework.security.extensions.kerberos.KerberosTicketValidator.KerberosTicketValidation;
|
||||
import org.springframework.security.extensions.kerberos.web.SpnegoAuthenticationProcessingFilter;
|
||||
|
||||
/**
|
||||
* Holds the Kerberos/SPNEGO token for requesting a kerberized service
|
||||
* and is also the output of <code>KerberosServiceAuthenticationProvider</code>.<br>
|
||||
* Holds the Kerberos/SPNEGO token for requesting a kerberized service and is
|
||||
* also the output of <code>KerberosServiceAuthenticationProvider</code>.<br>
|
||||
* Will mostly be created in <code>SpnegoAuthenticationProcessingFilter</code>
|
||||
* and authenticated in <code>KerberosServiceAuthenticationProvider</code>.
|
||||
*
|
||||
* This token cannot be re-authenticated, as you will get a Kerberos Reply error.
|
||||
* This token cannot be re-authenticated, as you will get a Kerberos Reply
|
||||
* error.
|
||||
*
|
||||
* @author Mike Wiesner
|
||||
* @author Jeremy Stone
|
||||
* @since 1.0
|
||||
* @see KerberosServiceAuthenticationProvider
|
||||
* @see SpnegoAuthenticationProcessingFilter
|
||||
*/
|
||||
|
||||
public class KerberosServiceRequestToken extends AbstractAuthenticationToken {
|
||||
|
||||
private static final long serialVersionUID = 395488921064775014L;
|
||||
|
||||
private final byte[] token;
|
||||
|
||||
private final Object principal;
|
||||
|
||||
/** Creates an authenticated token, normally used as an output of an authentication provider.
|
||||
* @param principal the user principal (mostly of instance <code>UserDetails</code>
|
||||
private final transient KerberosTicketValidation ticketValidation;
|
||||
|
||||
/**
|
||||
* Creates an authenticated token, normally used as an output of an
|
||||
* authentication provider.
|
||||
*
|
||||
* @param principal the user principal (mostly of instance <code>UserDetails</code>)
|
||||
* @param ticketValidation result of ticket validation
|
||||
* @param authorities the authorities which are granted to the user
|
||||
* @param token the Kerberos/SPNEGO token
|
||||
* @see UserDetails
|
||||
*/
|
||||
public KerberosServiceRequestToken(Object principal, Collection<? extends GrantedAuthority> authorities, byte[] token) {
|
||||
public KerberosServiceRequestToken(Object principal, KerberosTicketValidation ticketValidation,
|
||||
Collection<? extends GrantedAuthority> authorities, byte[] token) {
|
||||
super(authorities);
|
||||
this.token = token;
|
||||
this.principal = principal;
|
||||
this.ticketValidation = ticketValidation;
|
||||
super.setAuthenticated(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unauthenticated instance which should then be authenticated by
|
||||
* <code>KerberosServiceAuthenticationProvider/code>
|
||||
* <code>KerberosServiceAuthenticationProvider/code>.
|
||||
*
|
||||
* @param token Kerberos/SPNEGO token
|
||||
* @see KerberosServiceAuthenticationProvider
|
||||
@@ -66,6 +86,7 @@ public class KerberosServiceRequestToken extends AbstractAuthenticationToken {
|
||||
public KerberosServiceRequestToken(byte[] token) {
|
||||
super(null);
|
||||
this.token = token;
|
||||
this.ticketValidation = null;
|
||||
this.principal = null;
|
||||
}
|
||||
|
||||
@@ -114,4 +135,96 @@ public class KerberosServiceRequestToken extends AbstractAuthenticationToken {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ticket validation
|
||||
*
|
||||
* @return the ticket validation (which will be null if the token is unauthenticated)
|
||||
*/
|
||||
public KerberosTicketValidation getTicketValidation() {
|
||||
return ticketValidation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an authenticated token has a response token
|
||||
*
|
||||
* @return whether a response token is available
|
||||
*/
|
||||
public boolean hasResponseToken() {
|
||||
return ticketValidation != null && ticketValidation.responseToken() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (Base64) encoded response token assuming one is available.
|
||||
*
|
||||
* @return encoded response token
|
||||
*/
|
||||
public String getEncodedResponseToken() {
|
||||
if (!hasResponseToken())
|
||||
throw new IllegalStateException("Unauthenticated or no response token");
|
||||
|
||||
try {
|
||||
return new String(Base64.encode(ticketValidation.responseToken()), "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException("Unable to encode response token", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwraps an encrypted message using the gss context
|
||||
*
|
||||
* @param data the data
|
||||
* @param offset data offset
|
||||
* @param length data length
|
||||
* @return the decrypted message
|
||||
* @throws PrivilegedActionException
|
||||
*/
|
||||
public byte[] decrypt(final byte[] data, final int offset, final int length) throws PrivilegedActionException {
|
||||
return Subject.doAs(getTicketValidation().subject(), new PrivilegedExceptionAction<byte[]>() {
|
||||
public byte[] run() throws Exception {
|
||||
final GSSContext context = getTicketValidation().getGssContext();
|
||||
return context.unwrap(data, offset, length, new MessageProp(true));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwraps an encrypted message using the gss context
|
||||
*
|
||||
* @param data
|
||||
* @return the decrypted message
|
||||
* @throws PrivilegedActionException
|
||||
*/
|
||||
public byte[] decrypt(final byte[] data) throws PrivilegedActionException {
|
||||
return decrypt(data, 0, data.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps an message using the gss context
|
||||
*
|
||||
* @param data
|
||||
* @param offset
|
||||
* @param length
|
||||
* @return the encrypted message
|
||||
* @throws PrivilegedActionException
|
||||
*/
|
||||
public byte[] encrypt(final byte[] data, final int offset, final int length) throws PrivilegedActionException {
|
||||
return Subject.doAs(getTicketValidation().subject(), new PrivilegedExceptionAction<byte[]>() {
|
||||
public byte[] run() throws Exception {
|
||||
final GSSContext context = getTicketValidation().getGssContext();
|
||||
return context.wrap(data, offset, length, new MessageProp(true));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps an message using the gss context
|
||||
*
|
||||
* @param data
|
||||
* @return the encrypted message
|
||||
* @throws PrivilegedActionException
|
||||
*/
|
||||
public byte[] encrypt(final byte[] data) throws PrivilegedActionException {
|
||||
return encrypt(data, 0, data.length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2009 the original author or authors.
|
||||
* Copyright 2009-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,27 +13,72 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.extensions.kerberos;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||
|
||||
import org.ietf.jgss.GSSContext;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
|
||||
/**
|
||||
* Implementations of this interface are used in
|
||||
* {@link KerberosServiceAuthenticationProvider} to validate a Kerberos/SPNEGO Ticket.
|
||||
* {@link KerberosServiceAuthenticationProvider} to validate a Kerberos/SPNEGO
|
||||
* Ticket.
|
||||
*
|
||||
* @author Mike Wiesner
|
||||
* @author Jeremy Stone
|
||||
* @since 1.0
|
||||
* @version $Id$
|
||||
* @see KerberosServiceAuthenticationProvider
|
||||
*/
|
||||
public interface KerberosTicketValidator {
|
||||
|
||||
/** Validates a Kerberos/SPNEGO ticket.
|
||||
/**
|
||||
* Validates a Kerberos/SPNEGO ticket.
|
||||
*
|
||||
* @param token Kerbeos/SPNEGO ticket
|
||||
* @return authenticated kerberos principal
|
||||
* @throws BadCredentialsException if the ticket is not valid
|
||||
*/
|
||||
public String validateTicket(byte[] token) throws BadCredentialsException;
|
||||
public KerberosTicketValidation validateTicket(byte[] token)
|
||||
throws BadCredentialsException;
|
||||
|
||||
}
|
||||
/**
|
||||
* Result of ticket validation
|
||||
*/
|
||||
public static class KerberosTicketValidation {
|
||||
|
||||
private final String username;
|
||||
private final byte[] responseToken;
|
||||
private final GSSContext gssContext;
|
||||
private final String servicePrincipal;
|
||||
|
||||
KerberosTicketValidation(String username, String servicePrincipal, byte[] responseToken, GSSContext gssContext) {
|
||||
this.username = username;
|
||||
this.servicePrincipal = servicePrincipal;
|
||||
this.responseToken = responseToken;
|
||||
this.gssContext = gssContext;
|
||||
}
|
||||
|
||||
public String username() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public byte[] responseToken() {
|
||||
return responseToken;
|
||||
}
|
||||
|
||||
public GSSContext getGssContext() {
|
||||
return gssContext;
|
||||
}
|
||||
|
||||
public Subject subject() {
|
||||
final HashSet<KerberosPrincipal> princs = new HashSet<KerberosPrincipal>();
|
||||
princs.add(new KerberosPrincipal(servicePrincipal));
|
||||
return new Subject(false, princs, new HashSet<Object>(), new HashSet<Object>());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.springframework.util.Assert;
|
||||
* is needed.
|
||||
*
|
||||
* @author Mike Wiesner
|
||||
* @author Jeremy Stone
|
||||
* @since 1.0
|
||||
*/
|
||||
public class SunJaasKerberosTicketValidator implements KerberosTicketValidator, InitializingBean {
|
||||
@@ -53,18 +54,18 @@ public class SunJaasKerberosTicketValidator implements KerberosTicketValidator,
|
||||
private String servicePrincipal;
|
||||
private Resource keyTabLocation;
|
||||
private Subject serviceSubject;
|
||||
private boolean holdOnToGSSContext;
|
||||
private boolean debug = false;
|
||||
private static final Log LOG = LogFactory.getLog(SunJaasKerberosTicketValidator.class);
|
||||
|
||||
@Override
|
||||
public String validateTicket(byte[] token) {
|
||||
String username = null;
|
||||
public KerberosTicketValidation validateTicket(byte[] token) {
|
||||
try {
|
||||
username = Subject.doAs(this.serviceSubject, new KerberosValidateAction(token));
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw new BadCredentialsException("Kerberos validation not succesfull", e);
|
||||
return Subject.doAs(this.serviceSubject, new KerberosValidateAction(token));
|
||||
}
|
||||
catch (PrivilegedActionException e) {
|
||||
throw new BadCredentialsException("Kerberos validation not succesful", e);
|
||||
}
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -120,32 +121,48 @@ public class SunJaasKerberosTicketValidator implements KerberosTicketValidator,
|
||||
this.keyTabLocation = keyTabLocation;
|
||||
}
|
||||
|
||||
/** Enables the debug mode of the JAAS Kerberos login module
|
||||
/**
|
||||
* Enables the debug mode of the JAAS Kerberos login module.
|
||||
*
|
||||
* @param debug default is false
|
||||
*/
|
||||
public void setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether to hold on to the {@link GSSContext GSS security context} or
|
||||
* otherwise {@link GSSContext#dispose() dispose} of it immediately (the default behaviour).
|
||||
* <p>Holding on to the GSS context allows decrypt and encrypt operations for subsequent
|
||||
* interactions with the principal.
|
||||
*
|
||||
* @param holdOnToGSSContext true if should hold on to context
|
||||
*/
|
||||
public void setHoldOnToGSSContext(boolean holdOnToGSSContext) {
|
||||
this.holdOnToGSSContext = holdOnToGSSContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is needed, because the validation must run with previously generated JAAS subject
|
||||
* which belongs to the service principal and was loaded out of the keytab during startup.
|
||||
*/
|
||||
private static class KerberosValidateAction implements PrivilegedExceptionAction<String> {
|
||||
private class KerberosValidateAction implements PrivilegedExceptionAction<KerberosTicketValidation> {
|
||||
byte[] kerberosTicket;
|
||||
|
||||
public KerberosValidateAction(byte[] kerberosTicket) {
|
||||
this.kerberosTicket = kerberosTicket;
|
||||
}
|
||||
|
||||
public String run() throws Exception {
|
||||
GSSContext context = GSSManager.getInstance().createContext((GSSCredential) null);
|
||||
context.acceptSecContext(kerberosTicket, 0, kerberosTicket.length);
|
||||
String user = context.getSrcName().toString();
|
||||
context.dispose();
|
||||
return user;
|
||||
@Override
|
||||
public KerberosTicketValidation run() throws Exception {
|
||||
GSSContext context = GSSManager.getInstance().createContext((GSSCredential) null);
|
||||
byte[] responseToken = context.acceptSecContext(kerberosTicket, 0, kerberosTicket.length);
|
||||
String user = context.getSrcName().toString();
|
||||
if (!holdOnToGSSContext) {
|
||||
context.dispose();
|
||||
}
|
||||
return new KerberosTicketValidation(user, servicePrincipal, responseToken, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.security.extensions.kerberos.web;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.extensions.kerberos.KerberosServiceRequestToken;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
|
||||
/**
|
||||
* Adds a WWW-Authenticate (or other) header to the response following
|
||||
* successful authentication.
|
||||
*
|
||||
* @author Jeremy Stone
|
||||
*/
|
||||
public class ResponseHeaderSettingKerberosAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
|
||||
|
||||
private static final String NEGOTIATE_PREFIX = "Negotiate ";
|
||||
|
||||
private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
|
||||
|
||||
private String headerName = WWW_AUTHENTICATE;
|
||||
|
||||
private String headerPrefix = NEGOTIATE_PREFIX;
|
||||
|
||||
/**
|
||||
* Sets the name of the header to set. By default this is 'WWW-Authenticate'.
|
||||
*
|
||||
* @param headerName the www authenticate header name
|
||||
*/
|
||||
public void setHeaderName(String headerName) {
|
||||
this.headerName = headerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the prefix for the encoded response token value. By
|
||||
* default this is 'Negotiate '.
|
||||
*
|
||||
* @param headerPrefix the negotiate prefix
|
||||
*/
|
||||
public void setHeaderPrefix(String headerPrefix) {
|
||||
this.headerPrefix = headerPrefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authentication) throws IOException, ServletException {
|
||||
KerberosServiceRequestToken auth = (KerberosServiceRequestToken) authentication;
|
||||
if (auth.hasResponseToken()) {
|
||||
response.addHeader(headerName, headerPrefix + auth.getEncodedResponseToken());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -103,6 +103,7 @@ import org.springframework.web.filter.GenericFilterBean;
|
||||
*
|
||||
*
|
||||
* @author Mike Wiesner
|
||||
* @author Jeremy Stone
|
||||
* @since 1.0
|
||||
* @see KerberosServiceAuthenticationProvider
|
||||
* @see SpnegoEntryPoint
|
||||
@@ -133,11 +134,11 @@ public class SpnegoAuthenticationProcessingFilter extends GenericFilterBean {
|
||||
|
||||
String header = request.getHeader("Authorization");
|
||||
|
||||
if ((header != null) && header.startsWith("Negotiate ")) {
|
||||
if (header != null && (header.startsWith("Negotiate ") || header.startsWith("Kerberos "))) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Received Negotiate Header for request " + request.getRequestURL() + ": " + header);
|
||||
}
|
||||
byte[] base64Token = header.substring(10).getBytes("UTF-8");
|
||||
byte[] base64Token = header.substring(header.indexOf(" ") + 1).getBytes("UTF-8");
|
||||
byte[] kerberosTicket = Base64.decode(base64Token);
|
||||
KerberosServiceRequestToken authenticationRequest = new KerberosServiceRequestToken(kerberosTicket);
|
||||
authenticationRequest.setDetails(authenticationDetailsSource.buildDetails(request));
|
||||
|
||||
@@ -34,11 +34,13 @@ import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.extensions.kerberos.KerberosTicketValidator.KerberosTicketValidation;
|
||||
|
||||
/**
|
||||
* Test class for {@link KerberosServiceAuthenticationProvider}
|
||||
*
|
||||
* @author Mike Wiesner
|
||||
* @author Jeremy Stone
|
||||
* @since 1.0
|
||||
*/
|
||||
public class KerberosServiceAuthenticationProviderTest {
|
||||
@@ -49,7 +51,11 @@ public class KerberosServiceAuthenticationProviderTest {
|
||||
|
||||
// data
|
||||
private static final byte[] TEST_TOKEN = "TestToken".getBytes();
|
||||
private static final byte[] RESPONSE_TOKEN = "ResponseToken".getBytes();
|
||||
private static final String TEST_USER = "Testuser@SPRINGSOURCE.ORG";
|
||||
|
||||
private static final KerberosTicketValidation TICKET_VALIDATION = new KerberosTicketValidation(TEST_USER, "XXX", RESPONSE_TOKEN, null);
|
||||
|
||||
private static final List<GrantedAuthority> AUTHORITY_LIST = AuthorityUtils.createAuthorityList("ROLE_ADMIN");
|
||||
private static final UserDetails USER_DETAILS = new User(TEST_USER, "empty", true, true, true,true, AUTHORITY_LIST);
|
||||
private static final KerberosServiceRequestToken INPUT_TOKEN = new KerberosServiceRequestToken(TEST_TOKEN);
|
||||
@@ -109,7 +115,7 @@ public class KerberosServiceAuthenticationProviderTest {
|
||||
@Test(expected=UsernameNotFoundException.class)
|
||||
public void testUsernameNotFound() throws Exception {
|
||||
// stubbing
|
||||
when(ticketValidator.validateTicket(TEST_TOKEN)).thenReturn(TEST_USER);
|
||||
when(ticketValidator.validateTicket(TEST_TOKEN)).thenReturn(TICKET_VALIDATION);
|
||||
when(userDetailsService.loadUserByUsername(TEST_USER)).thenThrow(new UsernameNotFoundException(""));
|
||||
|
||||
// testing
|
||||
@@ -128,7 +134,7 @@ public class KerberosServiceAuthenticationProviderTest {
|
||||
|
||||
private Authentication callProviderAndReturnUser(UserDetails userDetails, Authentication inputToken) {
|
||||
// stubbing
|
||||
when(ticketValidator.validateTicket(TEST_TOKEN)).thenReturn(TEST_USER);
|
||||
when(ticketValidator.validateTicket(TEST_TOKEN)).thenReturn(TICKET_VALIDATION);
|
||||
when(userDetailsService.loadUserByUsername(TEST_USER)).thenReturn(userDetails);
|
||||
|
||||
// testing
|
||||
|
||||
@@ -15,8 +15,13 @@
|
||||
*/
|
||||
package org.springframework.security.extensions.kerberos.web;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -39,6 +44,7 @@ import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.extensions.kerberos.KerberosServiceRequestToken;
|
||||
import org.springframework.security.extensions.kerberos.KerberosTicketValidator.KerberosTicketValidation;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
@@ -47,27 +53,45 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS
|
||||
* Test class for {@link SpnegoAuthenticationProcessingFilter}
|
||||
*
|
||||
* @author Mike Wiesner
|
||||
* @author Jeremy Stone
|
||||
* @since 1.0
|
||||
*/
|
||||
public class SpnegoAuthenticationProcessingFilterTest {
|
||||
|
||||
private SpnegoAuthenticationProcessingFilter filter;
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
private HttpServletRequest request;
|
||||
|
||||
private HttpServletResponse response;
|
||||
|
||||
private FilterChain chain;
|
||||
|
||||
private AuthenticationSuccessHandler successHandler;
|
||||
|
||||
private AuthenticationFailureHandler failureHandler;
|
||||
|
||||
private WebAuthenticationDetailsSource detailsSource;
|
||||
|
||||
// data
|
||||
private static final byte[] TEST_TOKEN = "TestToken".getBytes();
|
||||
|
||||
private static final String TEST_TOKEN_BASE64 = "VGVzdFRva2Vu";
|
||||
private static final Authentication AUTHENTICATION = new KerberosServiceRequestToken("test",
|
||||
AuthorityUtils.createAuthorityList("ROLE_ADMIN"), TEST_TOKEN);
|
||||
|
||||
private static KerberosTicketValidation UNUSED_TICKET_VALIDATION = mock(KerberosTicketValidation.class);
|
||||
|
||||
private static final Authentication AUTHENTICATION = new KerberosServiceRequestToken(
|
||||
"test", UNUSED_TICKET_VALIDATION, AuthorityUtils.createAuthorityList("ROLE_ADMIN"),
|
||||
TEST_TOKEN);
|
||||
|
||||
private static final String HEADER = "Authorization";
|
||||
private static final String TOKEN_PREFIX = "Negotiate ";
|
||||
private static final BadCredentialsException BCE = new BadCredentialsException("");
|
||||
|
||||
private static final String TOKEN_PREFIX_NEG = "Negotiate ";
|
||||
|
||||
private static final String TOKEN_PREFIX_KERB = "Kerberos ";
|
||||
|
||||
private static final BadCredentialsException BCE = new BadCredentialsException("");
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
@@ -84,29 +108,44 @@ public class SpnegoAuthenticationProcessingFilterTest {
|
||||
|
||||
@Test
|
||||
public void testEverythingWorks() throws Exception {
|
||||
everythingWorks();
|
||||
everythingWorks(TOKEN_PREFIX_NEG);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEverythingWorks_Kerberos() throws Exception {
|
||||
everythingWorks(TOKEN_PREFIX_KERB);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEverythingWorksWithHandlers() throws Exception {
|
||||
createHandler();
|
||||
everythingWorks();
|
||||
verify(successHandler).onAuthenticationSuccess(request, response, AUTHENTICATION);
|
||||
verify(failureHandler, never()).onAuthenticationFailure(any(HttpServletRequest.class), any(HttpServletResponse.class),
|
||||
any(AuthenticationException.class));
|
||||
everythingWorksWithHandlers(TOKEN_PREFIX_NEG);
|
||||
}
|
||||
|
||||
private void everythingWorks() throws IOException, ServletException {
|
||||
@Test
|
||||
public void testEverythingWorksWithHandlers_Kerberos() throws Exception {
|
||||
everythingWorksWithHandlers(TOKEN_PREFIX_KERB);
|
||||
}
|
||||
|
||||
private void everythingWorksWithHandlers(String tokenPrefix) throws Exception {
|
||||
createHandler();
|
||||
everythingWorks(tokenPrefix);
|
||||
verify(successHandler).onAuthenticationSuccess(request, response, AUTHENTICATION);
|
||||
verify(failureHandler, never()).onAuthenticationFailure(any(HttpServletRequest.class),
|
||||
any(HttpServletResponse.class), any(AuthenticationException.class));
|
||||
}
|
||||
|
||||
private void everythingWorks(String tokenPrefix) throws IOException,
|
||||
ServletException {
|
||||
// stubbing
|
||||
when(request.getHeader(HEADER)).thenReturn(TOKEN_PREFIX + TEST_TOKEN_BASE64);
|
||||
KerberosServiceRequestToken requestToken = new KerberosServiceRequestToken(TEST_TOKEN);
|
||||
requestToken.setDetails(detailsSource.buildDetails(request));
|
||||
when(authenticationManager.authenticate(requestToken)).thenReturn(AUTHENTICATION);
|
||||
when(request.getHeader(HEADER)).thenReturn(tokenPrefix + TEST_TOKEN_BASE64);
|
||||
KerberosServiceRequestToken requestToken = new KerberosServiceRequestToken(TEST_TOKEN);
|
||||
requestToken.setDetails(detailsSource.buildDetails(request));
|
||||
when(authenticationManager.authenticate(requestToken)).thenReturn(AUTHENTICATION);
|
||||
|
||||
// testing
|
||||
filter.doFilter(request, response, chain);
|
||||
verify(chain).doFilter(request, response);
|
||||
assertEquals(AUTHENTICATION, SecurityContextHolder.getContext().getAuthentication());
|
||||
filter.doFilter(request, response, chain);
|
||||
verify(chain).doFilter(request, response);
|
||||
assertEquals(AUTHENTICATION, SecurityContextHolder.getContext().getAuthentication());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -114,50 +153,53 @@ public class SpnegoAuthenticationProcessingFilterTest {
|
||||
filter.doFilter(request, response, chain);
|
||||
// If the header is not present, the filter is not allowed to call
|
||||
// authenticate()
|
||||
verify(authenticationManager, never()).authenticate(any(Authentication.class));
|
||||
verify(authenticationManager, never()).authenticate(any(Authentication.class));
|
||||
// chain should go on
|
||||
verify(chain).doFilter(request, response);
|
||||
assertEquals(null, SecurityContextHolder.getContext().getAuthentication());
|
||||
verify(chain).doFilter(request, response);
|
||||
assertEquals(null, SecurityContextHolder.getContext().getAuthentication());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationFails() throws Exception {
|
||||
authenticationFails();
|
||||
verify(response).setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
verify(response).setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationFailsWithHandlers() throws Exception {
|
||||
createHandler();
|
||||
authenticationFails();
|
||||
verify(failureHandler).onAuthenticationFailure(request, response, BCE);
|
||||
verify(successHandler, never()).onAuthenticationSuccess(any(HttpServletRequest.class), any(HttpServletResponse.class),
|
||||
any(Authentication.class));
|
||||
verify(response, never()).setStatus(anyInt());
|
||||
createHandler();
|
||||
authenticationFails();
|
||||
verify(failureHandler).onAuthenticationFailure(request, response, BCE);
|
||||
verify(successHandler, never()).onAuthenticationSuccess(any(HttpServletRequest.class),
|
||||
any(HttpServletResponse.class), any(Authentication.class));
|
||||
verify(response, never()).setStatus(anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlreadyAuthenticated() throws Exception {
|
||||
try {
|
||||
Authentication existingAuth = new UsernamePasswordAuthenticationToken("mike", "mike",
|
||||
AuthorityUtils.createAuthorityList("ROLE_TEST"));
|
||||
SecurityContextHolder.getContext().setAuthentication(existingAuth);
|
||||
when(request.getHeader(HEADER)).thenReturn(TOKEN_PREFIX + TEST_TOKEN_BASE64);
|
||||
filter.doFilter(request, response, chain);
|
||||
verify(authenticationManager, never()).authenticate(any(Authentication.class));
|
||||
} finally {
|
||||
Authentication existingAuth = new UsernamePasswordAuthenticationToken("mike", "mike",
|
||||
AuthorityUtils.createAuthorityList("ROLE_TEST"));
|
||||
SecurityContextHolder.getContext().setAuthentication(existingAuth);
|
||||
when(request.getHeader(HEADER)).thenReturn(TOKEN_PREFIX_NEG + TEST_TOKEN_BASE64);
|
||||
filter.doFilter(request, response, chain);
|
||||
verify(authenticationManager, never()).authenticate(any(Authentication.class));
|
||||
}
|
||||
finally {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlreadyAuthenticatedWithNotAuthenticatedToken() throws Exception {
|
||||
public void testAlreadyAuthenticatedWithNotAuthenticatedToken()
|
||||
throws Exception {
|
||||
try {
|
||||
// this token is not authenticated yet!
|
||||
Authentication existingAuth = new UsernamePasswordAuthenticationToken("mike", "mike");
|
||||
SecurityContextHolder.getContext().setAuthentication(existingAuth);
|
||||
everythingWorks();
|
||||
} finally {
|
||||
Authentication existingAuth = new UsernamePasswordAuthenticationToken("mike", "mike");
|
||||
SecurityContextHolder.getContext().setAuthentication(existingAuth);
|
||||
everythingWorks(TOKEN_PREFIX_NEG);
|
||||
}
|
||||
finally {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
}
|
||||
@@ -165,11 +207,12 @@ public class SpnegoAuthenticationProcessingFilterTest {
|
||||
@Test
|
||||
public void testAlreadyAuthenticatedWithAnonymousToken() throws Exception {
|
||||
try {
|
||||
Authentication existingAuth = new AnonymousAuthenticationToken("test", "mike",
|
||||
AuthorityUtils.createAuthorityList("ROLE_TEST"));
|
||||
SecurityContextHolder.getContext().setAuthentication(existingAuth);
|
||||
everythingWorks();
|
||||
} finally {
|
||||
Authentication existingAuth = new AnonymousAuthenticationToken("test", "mike",
|
||||
AuthorityUtils.createAuthorityList("ROLE_TEST"));
|
||||
SecurityContextHolder.getContext().setAuthentication(existingAuth);
|
||||
everythingWorks(TOKEN_PREFIX_NEG);
|
||||
}
|
||||
finally {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
}
|
||||
@@ -177,26 +220,27 @@ public class SpnegoAuthenticationProcessingFilterTest {
|
||||
@Test
|
||||
public void testAlreadyAuthenticatedNotActive() throws Exception {
|
||||
try {
|
||||
Authentication existingAuth = new UsernamePasswordAuthenticationToken("mike", "mike",
|
||||
AuthorityUtils.createAuthorityList("ROLE_TEST"));
|
||||
SecurityContextHolder.getContext().setAuthentication(existingAuth);
|
||||
filter.setSkipIfAlreadyAuthenticated(false);
|
||||
everythingWorks();
|
||||
} finally {
|
||||
Authentication existingAuth = new UsernamePasswordAuthenticationToken("mike", "mike",
|
||||
AuthorityUtils.createAuthorityList("ROLE_TEST"));
|
||||
SecurityContextHolder.getContext().setAuthentication(existingAuth);
|
||||
filter.setSkipIfAlreadyAuthenticated(false);
|
||||
everythingWorks(TOKEN_PREFIX_NEG);
|
||||
}
|
||||
finally {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
private void authenticationFails() throws IOException, ServletException {
|
||||
// stubbing
|
||||
when(request.getHeader(HEADER)).thenReturn(TOKEN_PREFIX + TEST_TOKEN_BASE64);
|
||||
when(authenticationManager.authenticate(any(Authentication.class))).thenThrow(BCE);
|
||||
when(request.getHeader(HEADER)).thenReturn(TOKEN_PREFIX_NEG + TEST_TOKEN_BASE64);
|
||||
when(authenticationManager.authenticate(any(Authentication.class))).thenThrow(BCE);
|
||||
|
||||
// testing
|
||||
filter.doFilter(request, response, chain);
|
||||
// chain should stop here and it should send back a 500
|
||||
// future version should call some error handler
|
||||
verify(chain, never()).doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
verify(chain, never()).doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
}
|
||||
|
||||
private void createHandler() {
|
||||
|
||||
Reference in New Issue
Block a user