diff --git a/spring-security-kerberos-client/src/test/java/org/springframework/security/extensions/kerberos/client/KerberosRestTemplateTests.java b/spring-security-kerberos-client/src/test/java/org/springframework/security/extensions/kerberos/client/KerberosRestTemplateTests.java index 735b3f2..12b5fbd 100644 --- a/spring-security-kerberos-client/src/test/java/org/springframework/security/extensions/kerberos/client/KerberosRestTemplateTests.java +++ b/spring-security-kerberos-client/src/test/java/org/springframework/security/extensions/kerberos/client/KerberosRestTemplateTests.java @@ -19,6 +19,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import java.io.File; +import java.io.IOException; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -46,12 +47,16 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.security.extensions.kerberos.test.KerberosSecurityTestcase; import org.springframework.security.extensions.kerberos.test.MiniKdc; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.client.DefaultResponseErrorHandler; +import org.springframework.web.client.RestTemplate; public class KerberosRestTemplateTests extends KerberosSecurityTestcase { @@ -96,6 +101,42 @@ public class KerberosRestTemplateTests extends KerberosSecurityTestcase { assertThat(response, is("home")); } + @Test + public void testSpnegoWithForward() 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); + + context = SpringApplication.run(new Object[] { WebSecurityConfigSpnegoForward.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; + + // TODO: should tweak minikdc so that we can use kerberos principals + // which are not valid, for now just use plain RestTemplate + + // just checking that we get 401 which we skip and + // get login page content + RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); + restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { + @Override + public void handleError(ClientHttpResponse response) throws IOException { + } + }); + + String response = restTemplate.getForObject("http://" + host + ":" + port + "/hello", String.class); + assertThat(response, is("login")); + } + protected static class PortInitListener implements ApplicationListener { public int port; @@ -136,6 +177,12 @@ public class KerberosRestTemplateTests extends KerberosSecurityTestcase { return "home"; } + @RequestMapping(method = RequestMethod.GET, value = "/login") + @ResponseBody + public String login() { + return "login"; + } + } @Configuration diff --git a/spring-security-kerberos-client/src/test/java/org/springframework/security/extensions/kerberos/client/WebSecurityConfigSpnegoForward.java b/spring-security-kerberos-client/src/test/java/org/springframework/security/extensions/kerberos/client/WebSecurityConfigSpnegoForward.java new file mode 100644 index 0000000..4d699b3 --- /dev/null +++ b/spring-security-kerberos-client/src/test/java/org/springframework/security/extensions/kerberos/client/WebSecurityConfigSpnegoForward.java @@ -0,0 +1,110 @@ +/* + * 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.SpnegoAuthenticationProcessingFilter; +import org.springframework.security.extensions.kerberos.web.SpnegoEntryPoint; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +@Configuration +@EnableWebMvcSecurity +public class WebSecurityConfigSpnegoForward 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", "/login").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("/login"); + } + + @Bean + public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter( + AuthenticationManager authenticationManager) { + SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter(); + 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")); + } + + } + +}