diff --git a/build.gradle b/build.gradle
index 7bf54b3..70e2487 100644
--- a/build.gradle
+++ b/build.gradle
@@ -101,16 +101,22 @@ project('spring-security-kerberos-core') {
description = 'Spring Security Kerberos Core'
dependencies {
compile "org.springframework:spring-core:$springVersion"
- compile "org.springframework:spring-beans:$springVersion"
- compile "org.springframework:spring-aop:$springVersion"
- compile "org.springframework:spring-expression:$springVersion"
- compile "org.springframework:spring-context:$springVersion"
- compile "org.springframework:spring-tx:$springVersion"
- compile "org.springframework:spring-jdbc:$springVersion"
+ compile "org.springframework.security:spring-security-core:$springSecurityVersion"
+ }
+}
+
+project('spring-security-kerberos-web') {
+ description = 'Spring Security Kerberos Web'
+ dependencies {
+ compile project(":spring-security-kerberos-core")
+ compile "org.springframework:spring-core:$springVersion"
compile "org.springframework:spring-web:$springVersion"
- compile "org.springframework.security:spring-security-config:$springSecurityVersion"
compile "org.springframework.security:spring-security-web:$springSecurityVersion"
+
compile("javax.servlet:javax.servlet-api:$servletApi3Version", optional)
+
+ testCompile "org.springframework.security:spring-security-config:$springSecurityVersion"
+ testCompile "org.springframework:spring-test:$springVersion"
}
}
@@ -125,8 +131,12 @@ project('spring-security-kerberos-client') {
compile project(":spring-security-kerberos-core")
compile "org.springframework:spring-web:$springVersion"
compile "org.apache.httpcomponents:httpclient:$httpclientVersion"
+
optional("org.springframework.security:spring-security-ldap:$springSecurityVersion")
+
testCompile project(":spring-security-kerberos-test")
+ testCompile project(":spring-security-kerberos-web")
+ testCompile "org.springframework.security:spring-security-config:$springSecurityVersion"
testCompile "org.springframework.boot:spring-boot-autoconfigure:$springBootVersion"
testRuntime "org.apache.tomcat.embed:tomcat-embed-core:$tomcatEmbedVersion"
testRuntime "org.apache.tomcat.embed:tomcat-embed-logging-juli:$tomcatEmbedVersion"
@@ -174,8 +184,16 @@ configure(sampleServerProjects()) {
dependencies {
compile project(":spring-security-kerberos-samples-common")
compile project(":spring-security-kerberos-client")
+ compile project(":spring-security-kerberos-web")
compile "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion"
+ compile "org.springframework.security:spring-security-config:$springSecurityVersion"
compile "org.springframework.security:spring-security-ldap:$springSecurityVersion"
+ compile "org.springframework:spring-beans:$springVersion"
+ compile "org.springframework:spring-aop:$springVersion"
+ compile "org.springframework:spring-expression:$springVersion"
+ compile "org.springframework:spring-context:$springVersion"
+ compile "org.springframework:spring-tx:$springVersion"
+ compile "org.springframework:spring-jdbc:$springVersion"
testCompile "org.springframework:spring-test:$springVersion"
testCompile "org.hamcrest:hamcrest-core:$hamcrestVersion"
testCompile "org.hamcrest:hamcrest-library:$hamcrestVersion"
@@ -190,7 +208,15 @@ configure(sampleClientProjects()) {
dependencies {
compile project(":spring-security-kerberos-samples-common")
compile project(":spring-security-kerberos-client")
+ compile "org.springframework:spring-tx:$springVersion"
+ compile "org.springframework:spring-jdbc:$springVersion"
compile "org.springframework.boot:spring-boot-starter:$springBootVersion"
+ compile "org.springframework:spring-beans:$springVersion"
+ compile "org.springframework:spring-aop:$springVersion"
+ compile "org.springframework:spring-expression:$springVersion"
+ compile "org.springframework:spring-context:$springVersion"
+ compile "org.springframework:spring-tx:$springVersion"
+ compile "org.springframework:spring-jdbc:$springVersion"
testCompile "org.springframework:spring-test:$springVersion"
testCompile "org.hamcrest:hamcrest-core:$hamcrestVersion"
testCompile "org.hamcrest:hamcrest-library:$hamcrestVersion"
@@ -239,7 +265,8 @@ configure(rootProject) {
}
task copyDocsSamples(type: Copy) {
- from 'spring-security-kerberos-core/src/test/java/org/springframework/security/kerberos/docs/'
+ from 'spring-security-kerberos-web/src/test/java/org/springframework/security/kerberos/docs/'
+ from 'spring-security-kerberos-web/src/test/resources/org/springframework/security/kerberos/docs/'
from 'spring-security-kerberos-client/src/test/java/org/springframework/security/kerberos/client/docs/'
include '**/*.java'
include '**/*.xml'
diff --git a/settings.gradle b/settings.gradle
index 57107e2..92c9413 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -3,6 +3,7 @@ rootProject.name = 'spring-security-kerberos'
include 'spring-security-kerberos-core'
include 'spring-security-kerberos-client'
include 'spring-security-kerberos-test'
+include 'spring-security-kerberos-web'
include 'spring-security-kerberos-samples'
include 'spring-security-kerberos-samples:sec-server-client-auth'
include 'spring-security-kerberos-samples:sec-server-spnego-form-auth'
diff --git a/spring-security-kerberos-client/src/test/java/org/springframework/security/kerberos/client/WebSecurityConfig.java b/spring-security-kerberos-client/src/test/java/org/springframework/security/kerberos/client/WebSecurityConfig.java
index 074c3c8..8104253 100644
--- a/spring-security-kerberos-client/src/test/java/org/springframework/security/kerberos/client/WebSecurityConfig.java
+++ b/spring-security-kerberos-client/src/test/java/org/springframework/security/kerberos/client/WebSecurityConfig.java
@@ -29,10 +29,10 @@ 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.kerberos.KerberosServiceAuthenticationProvider;
-import org.springframework.security.kerberos.SunJaasKerberosTicketValidator;
-import org.springframework.security.kerberos.web.SpnegoAuthenticationProcessingFilter;
-import org.springframework.security.kerberos.web.SpnegoEntryPoint;
+import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider;
+import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator;
+import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter;
+import org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
@Configuration
diff --git a/spring-security-kerberos-client/src/test/java/org/springframework/security/kerberos/client/WebSecurityConfigSpnegoForward.java b/spring-security-kerberos-client/src/test/java/org/springframework/security/kerberos/client/WebSecurityConfigSpnegoForward.java
index 07805d1..30f02b0 100644
--- a/spring-security-kerberos-client/src/test/java/org/springframework/security/kerberos/client/WebSecurityConfigSpnegoForward.java
+++ b/spring-security-kerberos-client/src/test/java/org/springframework/security/kerberos/client/WebSecurityConfigSpnegoForward.java
@@ -29,10 +29,10 @@ 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.kerberos.KerberosServiceAuthenticationProvider;
-import org.springframework.security.kerberos.SunJaasKerberosTicketValidator;
-import org.springframework.security.kerberos.web.SpnegoAuthenticationProcessingFilter;
-import org.springframework.security.kerberos.web.SpnegoEntryPoint;
+import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider;
+import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator;
+import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter;
+import org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
@Configuration
diff --git a/spring-security-kerberos-client/src/test/java/org/springframework/security/kerberos/client/WebSecurityConfigSuccessHandler.java b/spring-security-kerberos-client/src/test/java/org/springframework/security/kerberos/client/WebSecurityConfigSuccessHandler.java
index 9d5240e..a690918 100644
--- a/spring-security-kerberos-client/src/test/java/org/springframework/security/kerberos/client/WebSecurityConfigSuccessHandler.java
+++ b/spring-security-kerberos-client/src/test/java/org/springframework/security/kerberos/client/WebSecurityConfigSuccessHandler.java
@@ -29,11 +29,11 @@ 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.kerberos.KerberosServiceAuthenticationProvider;
-import org.springframework.security.kerberos.SunJaasKerberosTicketValidator;
-import org.springframework.security.kerberos.web.ResponseHeaderSettingKerberosAuthenticationSuccessHandler;
-import org.springframework.security.kerberos.web.SpnegoAuthenticationProcessingFilter;
-import org.springframework.security.kerberos.web.SpnegoEntryPoint;
+import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider;
+import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator;
+import org.springframework.security.kerberos.web.authentication.ResponseHeaderSettingKerberosAuthenticationSuccessHandler;
+import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter;
+import org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
@Configuration
diff --git a/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/KerberosServiceAuthenticationProvider.java b/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/KerberosServiceAuthenticationProvider.java
deleted file mode 100644
index ff0a229..0000000
--- a/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/KerberosServiceAuthenticationProvider.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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.
- * 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.kerberos;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.security.authentication.AccountStatusUserDetailsChecker;
-import org.springframework.security.authentication.AuthenticationProvider;
-import org.springframework.security.core.Authentication;
-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.kerberos.KerberosTicketValidator.KerberosTicketValidation;
-import org.springframework.security.kerberos.web.SpnegoAuthenticationProcessingFilter;
-import org.springframework.util.Assert;
-
-/**
- *
Authentication Provider which validates Kerberos Service Tickets
- * or SPNEGO Tokens (which includes Kerberos Service Tickets).
- *
- *
It needs a KerberosTicketValidator, which contains the
- * code to validate the ticket, as this code is different between
- * SUN and IBM JRE.
- * It also needs an UserDetailsService to load the user properties
- * and the GrantedAuthorities, as we only get back the username
- * from Kerbeos
- *
- * You can see an example configuration in SpnegoAuthenticationProcessingFilter.
- *
- * @author Mike Wiesner
- * @author Jeremy Stone
- * @since 1.0
- * @see KerberosTicketValidator
- * @see UserDetailsService
- * @see SpnegoAuthenticationProcessingFilter
- */
-public class KerberosServiceAuthenticationProvider implements
- AuthenticationProvider, InitializingBean {
-
- private static final Log LOG = LogFactory.getLog(KerberosServiceAuthenticationProvider.class);
-
- private KerberosTicketValidator ticketValidator;
- private UserDetailsService userDetailsService;
- private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
-
- @Override
- public Authentication authenticate(Authentication authentication)
- throws AuthenticationException {
- KerberosServiceRequestToken auth = (KerberosServiceRequestToken) authentication;
- byte[] token = auth.getToken();
- LOG.debug("Try to validate Kerberos Token");
- 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, ticketValidation,
- userDetails.getAuthorities(), token);
- responseAuth.setDetails(authentication.getDetails());
- return responseAuth;
- }
-
- @Override
- public boolean supports(Class extends Object> auth) {
- return KerberosServiceRequestToken.class.isAssignableFrom(auth);
- }
-
- @Override
- public void afterPropertiesSet() throws Exception {
- Assert.notNull(this.ticketValidator, "ticketValidator must be specified");
- Assert.notNull(this.userDetailsService, "userDetailsService must be specified");
- }
-
- /**
- * The UserDetailsService to use, for loading the user properties
- * and the GrantedAuthorities.
- *
- * @param userDetailsService the new user details service
- */
- public void setUserDetailsService(UserDetailsService userDetailsService) {
- this.userDetailsService = userDetailsService;
- }
-
- /**
- * The KerberosTicketValidator 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 UserDetails
- * for a given authentication request.
- *
- * @param userDetails as retrieved from the {@link UserDetailsService}
- * @param authentication validated {@link KerberosServiceRequestToken}
- * @throws AuthenticationException AuthenticationException if the credentials could not be validated (generally a
- * BadCredentialsException, an AuthenticationServiceException)
- */
- protected void additionalAuthenticationChecks(UserDetails userDetails, KerberosServiceRequestToken authentication)
- throws AuthenticationException {
- }
-
-}
diff --git a/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/KerberosServiceRequestToken.java b/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/KerberosServiceRequestToken.java
deleted file mode 100644
index 45c2888..0000000
--- a/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/KerberosServiceRequestToken.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * 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.
- * 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.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.kerberos.KerberosTicketValidator.KerberosTicketValidation;
-import org.springframework.security.kerberos.web.SpnegoAuthenticationProcessingFilter;
-
-/**
- *
Holds the Kerberos/SPNEGO token for requesting a kerberized service and is
- * also the output of KerberosServiceAuthenticationProvider.
- *
Will mostly be created in SpnegoAuthenticationProcessingFilter
- * and authenticated in KerberosServiceAuthenticationProvider.
- *
- * 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;
-
- 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 UserDetails)
- * @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, 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
- * KerberosServiceAuthenticationProvider.
- *
- * @param token Kerberos/SPNEGO token
- * @see KerberosServiceAuthenticationProvider
- */
- public KerberosServiceRequestToken(byte[] token) {
- super(null);
- this.token = token;
- this.ticketValidation = null;
- this.principal = null;
- }
-
- /**
- * Calculates hashcode based on the Kerberos token
- */
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = super.hashCode();
- result = prime * result + Arrays.hashCode(token);
- return result;
- }
-
- /**
- * equals() is based only on the Kerberos token
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (!super.equals(obj))
- return false;
- if (getClass() != obj.getClass())
- return false;
- KerberosServiceRequestToken other = (KerberosServiceRequestToken) obj;
- if (!Arrays.equals(token, other.token))
- return false;
- return true;
- }
-
- @Override
- public Object getCredentials() {
- return null;
- }
-
- @Override
- public Object getPrincipal() {
- return this.principal;
- }
-
- /**
- * Returns the Kerberos token
- * @return the token data
- */
- public byte[] getToken() {
- 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 if jaas throws and error
- */
- public byte[] decrypt(final byte[] data, final int offset, final int length) throws PrivilegedActionException {
- return Subject.doAs(getTicketValidation().subject(), new PrivilegedExceptionAction() {
- 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 the data
- * @return the decrypted message
- * @throws PrivilegedActionException if jaas throws and error
- */
- public byte[] decrypt(final byte[] data) throws PrivilegedActionException {
- return decrypt(data, 0, data.length);
- }
-
- /**
- * Wraps an message using the gss context
- *
- * @param data the data
- * @param offset data offset
- * @param length data length
- * @return the encrypted message
- * @throws PrivilegedActionException if jaas throws and error
- */
- public byte[] encrypt(final byte[] data, final int offset, final int length) throws PrivilegedActionException {
- return Subject.doAs(getTicketValidation().subject(), new PrivilegedExceptionAction() {
- 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 the data
- * @return the encrypted message
- * @throws PrivilegedActionException if jaas throws and error
- */
- public byte[] encrypt(final byte[] data) throws PrivilegedActionException {
- return encrypt(data, 0, data.length);
- }
-
-}
diff --git a/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/KerberosAuthenticationProvider.java b/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosAuthenticationProvider.java
similarity index 97%
rename from spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/KerberosAuthenticationProvider.java
rename to spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosAuthenticationProvider.java
index dc07c64..440f6ee 100644
--- a/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/KerberosAuthenticationProvider.java
+++ b/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosAuthenticationProvider.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.security.kerberos;
+package org.springframework.security.kerberos.authentication;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
diff --git a/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/KerberosClient.java b/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosClient.java
similarity index 92%
rename from spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/KerberosClient.java
rename to spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosClient.java
index a4ab32e..27aa538 100644
--- a/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/KerberosClient.java
+++ b/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.security.kerberos;
+package org.springframework.security.kerberos.authentication;
/**
*
diff --git a/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosServiceAuthenticationProvider.java b/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosServiceAuthenticationProvider.java
new file mode 100644
index 0000000..8283f0c
--- /dev/null
+++ b/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosServiceAuthenticationProvider.java
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ * 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.kerberos.authentication;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.security.authentication.AccountStatusUserDetailsChecker;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.core.Authentication;
+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.util.Assert;
+
+/**
+ *
Authentication Provider which validates Kerberos Service Tickets
+ * or SPNEGO Tokens (which includes Kerberos Service Tickets).
+ *
+ *
It needs a KerberosTicketValidator, which contains the
+ * code to validate the ticket, as this code is different between
+ * SUN and IBM JRE.
+ * It also needs an UserDetailsService to load the user properties
+ * and the GrantedAuthorities, as we only get back the username
+ * from Kerbeos
+ *
+ * You can see an example configuration in SpnegoAuthenticationProcessingFilter.
+ *
+ * @author Mike Wiesner
+ * @author Jeremy Stone
+ * @since 1.0
+ * @see KerberosTicketValidator
+ * @see UserDetailsService
+ */
+public class KerberosServiceAuthenticationProvider implements
+ AuthenticationProvider, InitializingBean {
+
+ private static final Log LOG = LogFactory.getLog(KerberosServiceAuthenticationProvider.class);
+
+ private KerberosTicketValidator ticketValidator;
+ private UserDetailsService userDetailsService;
+ private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
+
+ @Override
+ public Authentication authenticate(Authentication authentication)
+ throws AuthenticationException {
+ KerberosServiceRequestToken auth = (KerberosServiceRequestToken) authentication;
+ byte[] token = auth.getToken();
+ LOG.debug("Try to validate Kerberos Token");
+ 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, ticketValidation,
+ userDetails.getAuthorities(), token);
+ responseAuth.setDetails(authentication.getDetails());
+ return responseAuth;
+ }
+
+ @Override
+ public boolean supports(Class extends Object> auth) {
+ return KerberosServiceRequestToken.class.isAssignableFrom(auth);
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ Assert.notNull(this.ticketValidator, "ticketValidator must be specified");
+ Assert.notNull(this.userDetailsService, "userDetailsService must be specified");
+ }
+
+ /**
+ * The UserDetailsService to use, for loading the user properties
+ * and the GrantedAuthorities.
+ *
+ * @param userDetailsService the new user details service
+ */
+ public void setUserDetailsService(UserDetailsService userDetailsService) {
+ this.userDetailsService = userDetailsService;
+ }
+
+ /**
+ * The KerberosTicketValidator 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 UserDetails
+ * for a given authentication request.
+ *
+ * @param userDetails as retrieved from the {@link UserDetailsService}
+ * @param authentication validated {@link KerberosServiceRequestToken}
+ * @throws AuthenticationException AuthenticationException if the credentials could not be validated (generally a
+ * BadCredentialsException, an AuthenticationServiceException)
+ */
+ protected void additionalAuthenticationChecks(UserDetails userDetails, KerberosServiceRequestToken authentication)
+ throws AuthenticationException {
+ }
+
+}
diff --git a/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosServiceRequestToken.java b/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosServiceRequestToken.java
new file mode 100644
index 0000000..a6c687c
--- /dev/null
+++ b/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosServiceRequestToken.java
@@ -0,0 +1,228 @@
+/*
+ * 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.
+ * 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.kerberos.authentication;
+
+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;
+
+/**
+ *
Holds the Kerberos/SPNEGO token for requesting a kerberized service and is
+ * also the output of KerberosServiceAuthenticationProvider.
+ *
Will mostly be created in SpnegoAuthenticationProcessingFilter
+ * and authenticated in KerberosServiceAuthenticationProvider.
+ *
+ * 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
+ */
+public class KerberosServiceRequestToken extends AbstractAuthenticationToken {
+
+ private static final long serialVersionUID = 395488921064775014L;
+
+ private final byte[] token;
+
+ private final Object principal;
+
+ 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 UserDetails)
+ * @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, 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
+ * KerberosServiceAuthenticationProvider.
+ *
+ * @param token Kerberos/SPNEGO token
+ * @see KerberosServiceAuthenticationProvider
+ */
+ public KerberosServiceRequestToken(byte[] token) {
+ super(null);
+ this.token = token;
+ this.ticketValidation = null;
+ this.principal = null;
+ }
+
+ /**
+ * Calculates hashcode based on the Kerberos token
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Arrays.hashCode(token);
+ return result;
+ }
+
+ /**
+ * equals() is based only on the Kerberos token
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ KerberosServiceRequestToken other = (KerberosServiceRequestToken) obj;
+ if (!Arrays.equals(token, other.token))
+ return false;
+ return true;
+ }
+
+ @Override
+ public Object getCredentials() {
+ return null;
+ }
+
+ @Override
+ public Object getPrincipal() {
+ return this.principal;
+ }
+
+ /**
+ * Returns the Kerberos token
+ * @return the token data
+ */
+ public byte[] getToken() {
+ 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 if jaas throws and error
+ */
+ public byte[] decrypt(final byte[] data, final int offset, final int length) throws PrivilegedActionException {
+ return Subject.doAs(getTicketValidation().subject(), new PrivilegedExceptionAction() {
+ 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 the data
+ * @return the decrypted message
+ * @throws PrivilegedActionException if jaas throws and error
+ */
+ public byte[] decrypt(final byte[] data) throws PrivilegedActionException {
+ return decrypt(data, 0, data.length);
+ }
+
+ /**
+ * Wraps an message using the gss context
+ *
+ * @param data the data
+ * @param offset data offset
+ * @param length data length
+ * @return the encrypted message
+ * @throws PrivilegedActionException if jaas throws and error
+ */
+ public byte[] encrypt(final byte[] data, final int offset, final int length) throws PrivilegedActionException {
+ return Subject.doAs(getTicketValidation().subject(), new PrivilegedExceptionAction() {
+ 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 the data
+ * @return the encrypted message
+ * @throws PrivilegedActionException if jaas throws and error
+ */
+ public byte[] encrypt(final byte[] data) throws PrivilegedActionException {
+ return encrypt(data, 0, data.length);
+ }
+
+}
diff --git a/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosTicketValidation.java b/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosTicketValidation.java
new file mode 100644
index 0000000..4707a40
--- /dev/null
+++ b/spring-security-kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/KerberosTicketValidation.java
@@ -0,0 +1,45 @@
+package org.springframework.security.kerberos.authentication;
+
+import java.util.HashSet;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosPrincipal;
+
+import org.ietf.jgss.GSSContext;
+
+/**
+ * Result of ticket validation
+ */
+public class KerberosTicketValidation {
+
+ private final String username;
+ private final byte[] responseToken;
+ private final GSSContext gssContext;
+ private final String servicePrincipal;
+
+ public 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 princs = new HashSet();
+ princs.add(new KerberosPrincipal(servicePrincipal));
+ return new Subject(false, princs, new HashSet