Author: coheigea
Date: Wed May 16 14:48:58 2012
New Revision: 1339203
URL: http://svn.apache.org/viewvc?rev=1339203&view=rev
Log:
Add an expires field to the ResponseState extracted from an
AuthenticationStatement SessionNotOnOrAfter value
Added:
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOValidatorResponse.java
- copied, changed from r1339160,
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java
Modified:
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractSSOSpHandler.java
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractServiceProviderFilter.java
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/RequestAssertionConsumerService.java
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLSSOResponseValidator.java
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/state/ResponseState.java
Modified:
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractSSOSpHandler.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractSSOSpHandler.java?rev=1339203&r1=1339202&r2=1339203&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractSSOSpHandler.java
(original)
+++
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractSSOSpHandler.java
Wed May 16 14:48:58 2012
@@ -63,8 +63,17 @@ public class AbstractSSOSpHandler {
return contextCookie;
}
- protected boolean isStateExpired(long stateCreatedAt) {
- return new Date().after(new Date(stateCreatedAt +
getStateTimeToLive()));
+ protected boolean isStateExpired(long stateCreatedAt, long expiresAt) {
+ Date currentTime = new Date();
+ if (currentTime.after(new Date(stateCreatedAt +
getStateTimeToLive()))) {
+ return true;
+ }
+
+ if (expiresAt > 0 && currentTime.after(new Date(expiresAt))) {
+ return true;
+ }
+
+ return false;
}
public void setStateProvider(SPStateManager stateProvider) {
Modified:
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractServiceProviderFilter.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractServiceProviderFilter.java?rev=1339203&r1=1339202&r2=1339203&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractServiceProviderFilter.java
(original)
+++
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/AbstractServiceProviderFilter.java
Wed May 16 14:48:58 2012
@@ -110,7 +110,7 @@ public abstract class AbstractServicePro
reportError("MISSING_RESPONSE_STATE");
return false;
}
- if (isStateExpired(responseState.getCreatedAt())) {
+ if (isStateExpired(responseState.getCreatedAt(),
responseState.getExpiresAt())) {
reportError("EXPIRED_RESPONSE_STATE");
getStateProvider().removeResponseState(contextKey);
return false;
Modified:
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/RequestAssertionConsumerService.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/RequestAssertionConsumerService.java?rev=1339203&r1=1339202&r2=1339203&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/RequestAssertionConsumerService.java
(original)
+++
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/RequestAssertionConsumerService.java
Wed May 16 14:48:58 2012
@@ -26,6 +26,7 @@ import java.io.UnsupportedEncodingExcept
import java.net.URI;
import java.net.URL;
import java.net.URLDecoder;
+import java.util.Date;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.UUID;
@@ -117,13 +118,22 @@ public class RequestAssertionConsumerSer
org.opensaml.saml2.core.Response samlResponse =
readSAMLResponse(true, encodedSamlResponse);
- validateSamlResponse(true, samlResponse, requestState);
+ // Validate the Response
+ validateSamlResponseProtocol(samlResponse);
+ SSOValidatorResponse validatorResponse =
+ validateSamlSSOResponse(true, samlResponse, requestState);
// Set the security context
String securityContextKey = UUID.randomUUID().toString();
long currentTime = System.currentTimeMillis();
- ResponseState responseState = new ResponseState(relayState,
currentTime);
+ Date notOnOrAfter = validatorResponse.getSessionNotOnOrAfter();
+ long expiresAt = 0;
+ if (notOnOrAfter != null) {
+ expiresAt = notOnOrAfter.getTime();
+ }
+ ResponseState responseState =
+ new ResponseState(relayState, currentTime, expiresAt);
getStateProvider().setResponseState(securityContextKey, responseState);
String contextCookie =
createCookie(SSOConstants.SECURITY_CONTEXT_TOKEN,
@@ -145,13 +155,22 @@ public class RequestAssertionConsumerSer
org.opensaml.saml2.core.Response samlResponse =
readSAMLResponse(false, encodedSamlResponse);
- validateSamlResponse(false, samlResponse, requestState);
+ // Validate the Response
+ validateSamlResponseProtocol(samlResponse);
+ SSOValidatorResponse validatorResponse =
+ validateSamlSSOResponse(false, samlResponse, requestState);
// Set the security context
String securityContextKey = UUID.randomUUID().toString();
long currentTime = System.currentTimeMillis();
- ResponseState responseState = new ResponseState(relayState,
currentTime);
+ Date notOnOrAfter = validatorResponse.getSessionNotOnOrAfter();
+ long expiresAt = 0;
+ if (notOnOrAfter != null) {
+ expiresAt = notOnOrAfter.getTime();
+ }
+ ResponseState responseState =
+ new ResponseState(relayState, currentTime, expiresAt);
getStateProvider().setResponseState(securityContextKey, responseState);
String contextCookie =
createCookie(SSOConstants.SECURITY_CONTEXT_TOKEN,
@@ -177,7 +196,7 @@ public class RequestAssertionConsumerSer
reportError("MISSING_REQUEST_STATE");
throw new WebApplicationException(400);
}
- if (isStateExpired(requestState.getCreatedAt())) {
+ if (isStateExpired(requestState.getCreatedAt(), 0)) {
reportError("EXPIRED_REQUEST_STATE");
throw new WebApplicationException(400);
}
@@ -241,28 +260,43 @@ public class RequestAssertionConsumerSer
return (org.opensaml.saml2.core.Response)responseObject;
}
- protected void validateSamlResponse(
+ /**
+ * Validate the received SAML Response as per the protocol
+ */
+ protected void validateSamlResponseProtocol(
+ org.opensaml.saml2.core.Response samlResponse
+ ) {
+ try {
+ SAMLProtocolResponseValidator protocolValidator = new
SAMLProtocolResponseValidator();
+ protocolValidator.validateSamlResponse(samlResponse,
getSignatureCrypto(), null);
+ } catch (WSSecurityException ex) {
+ reportError("INVALID_SAML_RESPONSE");
+ throw new WebApplicationException(400);
+ }
+ }
+
+ /**
+ * Validate the received SAML Response as per the Web SSO profile
+ */
+ protected SSOValidatorResponse validateSamlSSOResponse(
boolean postBinding,
org.opensaml.saml2.core.Response samlResponse,
RequestState requestState
) {
try {
- SAMLProtocolResponseValidator protocolValidator = new
SAMLProtocolResponseValidator();
- protocolValidator.validateSamlResponse(samlResponse,
getSignatureCrypto(), null);
-
SAMLSSOResponseValidator ssoResponseValidator = new
SAMLSSOResponseValidator();
ssoResponseValidator.setAssertionConsumerURL((String)jaxrsContext.get(Message.REQUEST_URL));
-
+
HttpServletRequest httpRequest =
(HttpServletRequest)jaxrsContext.get(AbstractHTTPDestination.HTTP_REQUEST);
ssoResponseValidator.setClientAddress(httpRequest.getRemoteAddr());
-
+
ssoResponseValidator.setIssuerIDP(requestState.getIdpServiceAddress());
ssoResponseValidator.setRequestId(requestState.getSamlRequestId());
ssoResponseValidator.setSpIdentifier(requestState.getIssuerId());
-
+
// TODO post binding
- ssoResponseValidator.validateSamlResponse(samlResponse, false);
+ return ssoResponseValidator.validateSamlResponse(samlResponse,
false);
} catch (WSSecurityException ex) {
reportError("INVALID_SAML_RESPONSE");
throw new WebApplicationException(400);
Modified:
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLSSOResponseValidator.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLSSOResponseValidator.java?rev=1339203&r1=1339202&r2=1339203&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLSSOResponseValidator.java
(original)
+++
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLSSOResponseValidator.java
Wed May 16 14:48:58 2012
@@ -18,6 +18,7 @@
*/
package org.apache.cxf.rs.security.saml.sso;
+import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
@@ -25,15 +26,12 @@ import org.apache.cxf.common.logging.Log
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.saml.ext.builder.SAML2Constants;
import org.opensaml.saml2.core.AudienceRestriction;
+import org.opensaml.saml2.core.AuthnStatement;
/**
* Validate a SAML 2.0 Protocol Response according to the Web SSO profile. The
Response
* should be validated by the SAMLProtocolResponseValidator first.
*
- * TODO If an <AuthnStatement> used to establish a security context for the
principal contains a
-SessionNotOnOrAfter attribute, the security context SHOULD be discarded once
this time is
-reached
-
TODO The service provider MUST ensure that bearer assertions are not replayed,
by maintaining the set of used
ID values for the length of time for which the assertion would be considered
valid based on the
NotOnOrAfter attribute in the <SubjectConfirmationData>.
@@ -52,9 +50,10 @@ public class SAMLSSOResponseValidator {
* Validate a SAML 2 Protocol Response
* @param samlResponse
* @param postBinding
+ * @return a SSOValidatorResponse object
* @throws WSSecurityException
*/
- public void validateSamlResponse(
+ public SSOValidatorResponse validateSamlResponse(
org.opensaml.saml2.core.Response samlResponse,
boolean postBinding
) throws WSSecurityException {
@@ -78,6 +77,7 @@ public class SAMLSSOResponseValidator {
// Validate Assertions
boolean foundValidSubject = false;
+ Date sessionNotOnOrAfter = null;
for (org.opensaml.saml2.core.Assertion assertion :
samlResponse.getAssertions()) {
// Check the Issuer
if (assertion.getIssuer() == null) {
@@ -99,6 +99,12 @@ public class SAMLSSOResponseValidator {
if (validateAuthenticationSubject(subject)) {
validateAudienceRestrictionCondition(assertion.getConditions());
foundValidSubject = true;
+ // Store Session NotOnOrAfter
+ for (AuthnStatement authnStatment :
assertion.getAuthnStatements()) {
+ if (authnStatment.getSessionNotOnOrAfter() != null) {
+ sessionNotOnOrAfter =
authnStatment.getSessionNotOnOrAfter().toDate();
+ }
+ }
}
}
@@ -109,6 +115,12 @@ public class SAMLSSOResponseValidator {
+ "the Subject Confirmation criteria");
throw new WSSecurityException(WSSecurityException.FAILURE,
"invalidSAMLsecurity");
}
+
+ SSOValidatorResponse validatorResponse = new SSOValidatorResponse();
+ validatorResponse.setResponseId(samlResponse.getID());
+ validatorResponse.setSessionNotOnOrAfter(sessionNotOnOrAfter);
+
+ return validatorResponse;
}
/**
Modified:
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java?rev=1339203&r1=1339202&r2=1339203&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java
(original)
+++
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java
Wed May 16 14:48:58 2012
@@ -23,7 +23,7 @@ public final class SSOConstants {
public static final String SAML_RESPONSE = "SAMLResponse";
public static final String RELAY_STATE = "RelayState";
public static final String SECURITY_CONTEXT_TOKEN =
"org.apache.cxf.websso.context";
- public static final long DEFAULT_STATE_TIME = 2 * 60 * 1000;
+ public static final long DEFAULT_STATE_TIME = 2L * 60L * 1000L;
private SSOConstants() {
Copied:
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOValidatorResponse.java
(from r1339160,
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java)
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOValidatorResponse.java?p2=cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOValidatorResponse.java&p1=cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java&r1=1339160&r2=1339203&rev=1339203&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOConstants.java
(original)
+++
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SSOValidatorResponse.java
Wed May 16 14:48:58 2012
@@ -18,14 +18,28 @@
*/
package org.apache.cxf.rs.security.saml.sso;
-public final class SSOConstants {
- public static final String SAML_REQUEST = "SAMLRequest";
- public static final String SAML_RESPONSE = "SAMLResponse";
- public static final String RELAY_STATE = "RelayState";
- public static final String SECURITY_CONTEXT_TOKEN =
"org.apache.cxf.websso.context";
- public static final long DEFAULT_STATE_TIME = 2 * 60 * 1000;
+import java.util.Date;
+
+/**
+ * Some information that encapsulates a successful validation by the
SAMLSSOResponseValidator
+ */
+public class SSOValidatorResponse {
+ private Date sessionNotOnOrAfter;
+ private String responseId;
+
+ public Date getSessionNotOnOrAfter() {
+ return sessionNotOnOrAfter;
+ }
+ public void setSessionNotOnOrAfter(Date sessionNotOnOrAfter) {
+ this.sessionNotOnOrAfter = sessionNotOnOrAfter;
+ }
+
+ public String getResponseId() {
+ return responseId;
+ }
- private SSOConstants() {
+ public void setResponseId(String responseId) {
+ this.responseId = responseId;
}
}
Modified:
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/state/ResponseState.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/state/ResponseState.java?rev=1339203&r1=1339202&r2=1339203&view=diff
==============================================================================
---
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/state/ResponseState.java
(original)
+++
cxf/trunk/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/state/ResponseState.java
Wed May 16 14:48:58 2012
@@ -22,15 +22,21 @@ public class ResponseState {
private String relayState;
private long createdAt;
+ private long expiresAt;
- public ResponseState(String relayState, long createdAt) {
+ public ResponseState(String relayState, long createdAt, long expiresAt) {
this.relayState = relayState;
this.createdAt = createdAt;
+ this.expiresAt = expiresAt;
}
public long getCreatedAt() {
return createdAt;
}
+
+ public long getExpiresAt() {
+ return expiresAt;
+ }
public String getRelayState() {
return relayState;