throw new UnmarshallingException("Unable to read serialized authentication request");
}
}
-
}
\ No newline at end of file
import org.apache.log4j.Logger;
import org.opensaml.common.IdentifierGenerator;
+import org.opensaml.common.SAMLObject;
import org.opensaml.common.binding.decoding.MessageDecoderFactory;
import org.opensaml.common.binding.encoding.MessageEncoderFactory;
import org.opensaml.saml2.metadata.provider.MetadataProvider;
/**
* Contextual object used to accumlate information as profile requests are being processed.
+ *
+ * @param <StatusType> type of Status object
*/
- protected class SAMLProfileRequestContext extends ShibbolethProfileRequestContext {
+ protected class SAMLProfileRequestContext<StatusType extends SAMLObject> extends ShibbolethProfileRequestContext {
/** Role descriptor name that the asserting party is operating in. */
private QName assertingPartyRole;
+++ /dev/null
-/*
- * Copyright [2006] [University Corporation for Advanced Internet Development, Inc.]
- *
- * 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 edu.internet2.middleware.shibboleth.idp.profile.saml2;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import org.apache.log4j.Logger;
-import org.joda.time.DateTime;
-import org.opensaml.Configuration;
-import org.opensaml.common.SAMLObjectBuilder;
-import org.opensaml.common.binding.BindingException;
-import org.opensaml.common.binding.encoding.MessageEncoder;
-import org.opensaml.saml2.core.Assertion;
-import org.opensaml.saml2.core.AuthnContext;
-import org.opensaml.saml2.core.AuthnContextClassRef;
-import org.opensaml.saml2.core.AuthnContextDeclRef;
-import org.opensaml.saml2.core.AuthnRequest;
-import org.opensaml.saml2.core.AuthnStatement;
-import org.opensaml.saml2.core.GetComplete;
-import org.opensaml.saml2.core.IDPEntry;
-import org.opensaml.saml2.core.IDPList;
-import org.opensaml.saml2.core.Issuer;
-import org.opensaml.saml2.core.RequestedAuthnContext;
-import org.opensaml.saml2.core.Response;
-import org.opensaml.saml2.core.Scoping;
-import org.opensaml.saml2.core.Status;
-import org.opensaml.saml2.core.StatusCode;
-import org.opensaml.saml2.core.Subject;
-import org.opensaml.saml2.core.SubjectConfirmation;
-import org.opensaml.saml2.metadata.AssertionConsumerService;
-import org.opensaml.saml2.metadata.Endpoint;
-import org.opensaml.saml2.metadata.RoleDescriptor;
-import org.opensaml.saml2.metadata.SPSSODescriptor;
-import org.opensaml.saml2.metadata.provider.MetadataProvider;
-import org.opensaml.saml2.metadata.provider.MetadataProviderException;
-import org.opensaml.xml.io.Unmarshaller;
-import org.opensaml.xml.io.UnmarshallingException;
-import org.opensaml.xml.parse.BasicParserPool;
-import org.opensaml.xml.parse.ParserPool;
-import org.opensaml.xml.parse.XMLParserException;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
-import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
-import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
-import edu.internet2.middleware.shibboleth.common.relyingparty.ProfileConfiguration;
-import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
-import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml2.AbstractSAML2ProfileConfiguration;
-import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml2.SSOConfiguration;
-import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationManager;
-import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
-import edu.internet2.middleware.shibboleth.idp.authn.Saml2LoginContext;
-
-/**
- * Abstract SAML 2.0 Authentication Request profile handler.
- */
-public abstract class AbstractAuthenticationRequest extends AbstractSAML2ProfileHandler {
-
- /**
- * Represents the internal state of a SAML 2.0 Authentiation Request while it's being processed by the IdP.
- */
- protected class AuthenticationRequestContext {
-
- /** The ProfileRequest. */
- protected ProfileRequest<ServletRequest> profileRequest;
-
- /** The ProfileResponse. */
- protected ProfileResponse<ServletResponse> profileResponse;
-
- /** The HttpServletRequest. */
- protected HttpServletRequest servletRequest;
-
- /** The HttpServletResponse. */
- protected HttpServletResponse servletResponse;
-
- /** The SAML 2.0 AuthnRequest. */
- protected AuthnRequest authnRequest;
-
- /** The issuer. */
- protected String issuer;
-
- /** The Subject. */
- protected Subject subject;
-
- /** The Response. */
- protected Response response;
-
- /** The IdP's LoginContext. */
- protected LoginContext loginContext;
-
- /** The RelyingPartyConfiguration. */
- protected RelyingPartyConfiguration rpConfig;
-
- /** The SSOConfiguration. */
- protected SSOConfiguration ssoConfig;
-
- /** The SPSSOConfiguration. */
- protected SPSSODescriptor spDescriptor;
-
- /** The AssertionConsumerService endpoint. */
- protected AssertionConsumerService assertionConsumerService;
-
- public AuthenticationRequestContext() {
- }
-
- public ProfileRequest<ServletRequest> getProfileRequest() {
- return profileRequest;
- }
-
- public void setProfileRequest(ProfileRequest<ServletRequest> profileRequest) {
- this.profileRequest = profileRequest;
- this.servletRequest = (HttpServletRequest) profileRequest.getRawRequest();
- }
-
- public ProfileResponse<ServletResponse> getProfileResponse() {
- return profileResponse;
- }
-
- public void setProfileResponse(ProfileResponse<ServletResponse> profileResponse) {
- this.profileResponse = profileResponse;
- this.servletResponse = (HttpServletResponse) profileResponse.getRawResponse();
- }
-
- public HttpServletRequest getServletRequest() {
- return servletRequest;
- }
-
- public void setServletRequest(HttpServletRequest servletRequest) {
- this.servletRequest = servletRequest;
- }
-
- public HttpServletResponse getServletResponse() {
- return servletResponse;
- }
-
- public void setServletResponse(HttpServletResponse servletResponse) {
- this.servletResponse = servletResponse;
- }
-
- public HttpSession getHttpSession() {
-
- if (getServletRequest() != null) {
- return getServletRequest().getSession();
- } else {
- return null;
- }
- }
-
- public AuthnRequest getAuthnRequest() {
- return authnRequest;
- }
-
- public void setAuthnRequest(AuthnRequest authnRequest) {
- this.authnRequest = authnRequest;
- }
-
- public String getIssuer() {
- return issuer;
- }
-
- public void setIssuer(String issuer) {
- this.issuer = issuer;
- }
-
- public Subject getSubject() {
- return subject;
- }
-
- public void setSubject(Subject subject) {
- this.subject = subject;
- }
-
- public LoginContext getLoginContext() {
- return loginContext;
- }
-
- public void setLoginContext(LoginContext loginContext) {
- this.loginContext = loginContext;
- }
-
- public RelyingPartyConfiguration getRpConfig() {
- return rpConfig;
- }
-
- public void setRpConfig(RelyingPartyConfiguration rpConfig) {
- this.rpConfig = rpConfig;
- }
-
- public SSOConfiguration getSsoConfig() {
- return ssoConfig;
- }
-
- public void setSsoConfig(SSOConfiguration ssoConfig) {
- this.ssoConfig = ssoConfig;
- }
-
- public SPSSODescriptor getSpDescriptor() {
- return spDescriptor;
- }
-
- public void setSpDescriptor(SPSSODescriptor spDescriptor) {
- this.spDescriptor = spDescriptor;
- }
-
- public Response getResponse() {
- return response;
- }
-
- public void setResponse(Response response) {
- this.response = response;
- }
-
- public AssertionConsumerService getAssertionConsumerService() {
- return assertionConsumerService;
- }
-
- public void setAssertionConsumerService(AssertionConsumerService assertionConsumerService) {
- this.assertionConsumerService = assertionConsumerService;
- }
-
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
-
- if (getClass() != obj.getClass()) {
- return false;
- }
-
- final edu.internet2.middleware.shibboleth.idp.profile.saml2.AbstractAuthenticationRequest.AuthenticationRequestContext other = (edu.internet2.middleware.shibboleth.idp.profile.saml2.AbstractAuthenticationRequest.AuthenticationRequestContext) obj;
-
- if (this.profileRequest != other.profileRequest
- && (this.profileRequest == null || !this.profileRequest.equals(other.profileRequest))) {
- return false;
- }
-
- if (this.profileResponse != other.profileResponse
- && (this.profileResponse == null || !this.profileResponse.equals(other.profileResponse))) {
- return false;
- }
-
- if (this.servletRequest != other.servletRequest
- && (this.servletRequest == null || !this.servletRequest.equals(other.servletRequest))) {
- return false;
- }
-
- if (this.servletResponse != other.servletResponse
- && (this.servletResponse == null || !this.servletResponse.equals(other.servletResponse))) {
- return false;
- }
-
- if (this.authnRequest != other.authnRequest
- && (this.authnRequest == null || !this.authnRequest.equals(other.authnRequest))) {
- return false;
- }
-
- if (this.issuer != other.issuer && (this.issuer == null || !this.issuer.equals(other.issuer))) {
- return false;
- }
-
- if (this.subject != other.subject && (this.subject == null || !this.subject.equals(other.subject))) {
- return false;
- }
-
- if (this.response != other.response && (this.response == null || !this.response.equals(other.response))) {
- return false;
- }
-
- if (this.loginContext != other.loginContext
- && (this.loginContext == null || !this.loginContext.equals(other.loginContext))) {
- return false;
- }
-
- if (this.rpConfig != other.rpConfig && (this.rpConfig == null || !this.rpConfig.equals(other.rpConfig))) {
- return false;
- }
-
- if (this.ssoConfig != other.ssoConfig
- && (this.ssoConfig == null || !this.ssoConfig.equals(other.ssoConfig))) {
- return false;
- }
-
- if (this.spDescriptor != other.spDescriptor
- && (this.spDescriptor == null || !this.spDescriptor.equals(other.spDescriptor))) {
- return false;
- }
-
- if (this.assertionConsumerService != other.assertionConsumerService
- && (this.assertionConsumerService == null || !this.assertionConsumerService
- .equals(other.assertionConsumerService))) {
- return false;
- }
-
- return true;
- }
-
- public int hashCode() {
- int hash = 7;
- return hash;
- }
-
- }
-
- /** Class logger. */
- private static final Logger log = Logger.getLogger(AbstractAuthenticationRequest.class);
-
- /** HttpSession key for the AuthenticationRequestContext. */
- protected static final String REQUEST_CONTEXT_SESSION_KEY = "edu.internet2.middleware.shibboleth.idp.profile.saml2.AuthenticationRequestContext";
-
- /** The path to the IdP's AuthenticationManager servlet */
- protected String authnMgrURL;
-
- /** AuthenticationManager to be used */
- protected AuthenticationManager authnMgr;
-
- /** A pool of XML parsers. */
- protected ParserPool parserPool;
-
- /** Builder for AuthnStatements. */
- protected SAMLObjectBuilder<AuthnStatement> authnStatementBuilder;
-
- /** Builder for AuthnContexts. */
- protected SAMLObjectBuilder<AuthnContext> authnContextBuilder;
-
- /** Builder for AuthnContextDeclRef's */
- protected SAMLObjectBuilder<AuthnContextDeclRef> authnContextDeclRefBuilder;
-
- /** Builder for AuthnContextClassRef's. */
- protected SAMLObjectBuilder<AuthnContextClassRef> authnContextClassRefBuilder;
-
- /**
- * Constructor.
- */
- public AbstractAuthenticationRequest() {
-
- parserPool = new BasicParserPool();
- authnStatementBuilder = (SAMLObjectBuilder<AuthnStatement>) getBuilderFactory().getBuilder(
- AuthnStatement.DEFAULT_ELEMENT_NAME);
- authnContextBuilder = (SAMLObjectBuilder<AuthnContext>) getBuilderFactory().getBuilder(
- AuthnContext.DEFAULT_ELEMENT_NAME);
- authnContextDeclRefBuilder = (SAMLObjectBuilder<AuthnContextDeclRef>) getBuilderFactory().getBuilder(
- AuthnContextDeclRef.DEFAULT_ELEMENT_NAME);
- authnContextClassRefBuilder = (SAMLObjectBuilder<AuthnContextClassRef>) getBuilderFactory().getBuilder(
- AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
- }
-
- /**
- * Set the Authentication Mananger.
- *
- * @param authnManager The IdP's AuthenticationManager.
- */
- public void setAuthenticationManager(AuthenticationManager authnManager) {
- this.authnMgr = authnMgr;
- }
-
- /**
- * Evaluate a SAML 2 AuthenticationRequest message.
- *
- * @param authnRequest A SAML 2 AuthenticationRequest
- * @param issuer The issuer of the authnRequest.
- * @param session The HttpSession of the request.
- * @param relyingParty The RelyingPartyConfiguration for the request.
- * @param ssoConfig The SSOConfiguration for the request.
- * @param spDescriptor The SPSSODescriptor for the request.
- *
- * @throws ProfileException On Error.
- */
- protected void evaluateRequest(final AuthenticationRequestContext requestContext) throws ProfileException {
-
- Response samlResponse;
-
- final AuthnRequest authnRequest = requestContext.getAuthnRequest();
- String issuer = requestContext.getIssuer();
- final HttpSession session = requestContext.getHttpSession();
- final RelyingPartyConfiguration relyingParty = requestContext.getRpConfig();
- final SSOConfiguration ssoConfig = requestContext.getSsoConfig();
- final SPSSODescriptor spDescriptor = requestContext.getSpDescriptor();
-
- LoginContext loginCtx = requestContext.getLoginContext();
- if (loginCtx.getAuthenticationOK()) {
-
- // the user successfully authenticated.
- // build an authentication assertion.
- samlResponse = buildResponse(authnRequest.getID(), new DateTime(), relyingParty.getProviderId(),
- buildStatus(StatusCode.SUCCESS_URI, null, null));
-
- DateTime now = new DateTime();
- Assertion assertion = buildAssertion(now, relyingParty, (AbstractSAML2ProfileConfiguration) ssoConfig);
- assertion.setSubject(requestContext.getSubject());
- setAuthenticationStatement(assertion, loginCtx, authnRequest);
- samlResponse.getAssertions().add(assertion);
-
- } else {
-
- // if authentication failed, encode the appropriate SAML error message.
- String failureMessage = loginCtx.getAuthenticationFailureMessage();
- Status failureStatus = buildStatus(StatusCode.RESPONDER_URI, StatusCode.AUTHN_FAILED_URI, failureMessage);
- samlResponse = buildResponse(authnRequest.getID(), new DateTime(), relyingParty.getProviderId(),
- failureStatus);
- }
-
- requestContext.setResponse(samlResponse);
- }
-
- /**
- * Build a SAML 2 Response element with basic fields populated.
- *
- * Failure handlers can send the returned response element to the RP. Success handlers should add the assertions
- * before sending it.
- *
- * @param inResponseTo The ID of the request this is in response to.
- * @param issueInstant The timestamp of this response.
- * @param issuer The URI of the RP issuing the response.
- * @param status The response's status code.
- *
- * @return The populated Response object.
- */
- protected Response buildResponse(String inResponseTo, final DateTime issueInstant, String issuer,
- final Status status) {
-
- Response response = getResponseBuilder().buildObject();
-
- Issuer i = getIssuerBuilder().buildObject();
- i.setValue(issuer);
-
- response.setVersion(SAML_VERSION);
- response.setID(getIdGenerator().generateIdentifier());
- response.setInResponseTo(inResponseTo);
- response.setIssueInstant(issueInstant);
- response.setIssuer(i);
- response.setStatus(status);
-
- return response;
- }
-
- /**
- * Check if the user has already been authenticated.
- *
- * @param httpSession the user's HttpSession.
- *
- * @return <code>true</code> if the user has been authenticated. otherwise <code>false</code>
- */
- protected boolean hasUserAuthenticated(final HttpSession httpSession) {
-
- // if the user has authenticated, their session will have a LoginContext
-
- Object o = httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
- return (o != null && o instanceof LoginContext);
- }
-
- /**
- * Check if the user has already been authenticated. If so, return the LoginContext. If not, redirect the user to
- * the AuthenticationManager.
- *
- * @param authnRequest The SAML 2 AuthnRequest.
- * @param httpSession The user's HttpSession.
- * @param request The user's HttpServletRequest.
- * @param response The user's HttpServletResponse.
- *
- * @throws ProfileException on error.
- */
- protected void authenticateUser(final AuthenticationRequestContext requestContext) throws ProfileException {
-
- AuthnRequest authnRequest = requestContext.getAuthnRequest();
- HttpSession httpSession = requestContext.getHttpSession();
- HttpServletRequest servletRequest = requestContext.getServletRequest();
- HttpServletResponse servletResponse = requestContext.getServletResponse();
-
- // Forward the request to the AuthenticationManager.
- // When the AuthenticationManager is done it will
- // forward the request back to this servlet.
-
- // push the AuthenticationRequestContext into the session so we have it
- // for the return leg.
- httpSession.setAttribute(REQUEST_CONTEXT_SESSION_KEY, requestContext);
-
- Saml2LoginContext loginCtx = new Saml2LoginContext(authnRequest);
- requestContext.setLoginContext(loginCtx);
- loginCtx.setProfileHandlerURL(servletRequest.getRequestURI());
-
- // the AuthenticationManager expects the LoginContext to be in the HttpSession.
- httpSession.setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginCtx);
- try {
- RequestDispatcher dispatcher = servletRequest.getRequestDispatcher(authnMgrURL);
- dispatcher.forward(servletRequest, servletResponse);
- } catch (IOException ex) {
- log.error("Error forwarding SAML 2 AuthnRequest " + authnRequest.getID() + " to AuthenticationManager", ex);
- throw new ProfileException("Error forwarding SAML 2 AuthnRequest " + authnRequest.getID()
- + " to AuthenticationManager", ex);
- } catch (ServletException ex) {
- log.error("Error forwarding SAML 2 AuthnRequest " + authnRequest.getID() + " to AuthenticationManager", ex);
- throw new ProfileException("Error forwarding SAML 2 AuthnRequest " + authnRequest.getID()
- + " to AuthenticationManager", ex);
- }
- }
-
- /**
- * Build an AuthnStatement and add it to an Assertion.
- *
- * @param assertion An empty SAML 2 Assertion object.
- * @param loginContext The processed login context for the AuthnRequest.
- * @param authnRequest The AuthnRequest to which this is in response.
- *
- * @throws ProfileException On error.
- */
- protected void setAuthenticationStatement(Assertion assertion, final LoginContext loginContext,
- final AuthnRequest authnRequest) throws ProfileException {
-
- // Build the AuthnCtx.
- // We need to determine if the user was authenticated
- // with an AuthnContextClassRef or a AuthnContextDeclRef
- AuthnContext authnCtx = buildAuthnCtx(authnRequest.getRequestedAuthnContext(), loginContext);
- if (authnCtx == null) {
- log.error("Error respond to SAML 2 AuthnRequest " + authnRequest.getID()
- + " : Unable to determine authentication method");
- }
-
- AuthnStatement stmt = authnStatementBuilder.buildObject();
- stmt.setAuthnInstant(loginContext.getAuthenticationInstant());
- stmt.setAuthnContext(authnCtx);
-
- // add the AuthnStatement to the Assertion
- List<AuthnStatement> authnStatements = assertion.getAuthnStatements();
- authnStatements.add(stmt);
- }
-
- /**
- * Create the AuthnContex object.
- *
- * To do this, we have to walk the AuthnRequest's RequestedAuthnContext object and compare any values we find to
- * what's set in the loginContext.
- *
- * @param requestedAuthnCtx The RequestedAuthnContext from the Authentication Request.
- * @param loginContext The processed LoginContext (it must contain the authn method).
- *
- * @return An AuthnCtx object on success or <code>null</code> on failure.
- */
- protected AuthnContext buildAuthnCtx(final RequestedAuthnContext requestedAuthnCtx, final LoginContext loginContext) {
-
- // this method assumes that only one URI will match.
-
- AuthnContext authnCtx = authnContextBuilder.buildObject();
- String authnMethod = loginContext.getAuthenticationMethod();
-
- List<AuthnContextClassRef> authnClasses = requestedAuthnCtx.getAuthnContextClassRefs();
- List<AuthnContextDeclRef> authnDeclRefs = requestedAuthnCtx.getAuthnContextDeclRefs();
-
- if (authnClasses != null) {
- for (AuthnContextClassRef classRef : authnClasses) {
- if (classRef != null) {
- String s = classRef.getAuthnContextClassRef();
- if (s != null && authnMethod.equals(s)) {
- AuthnContextClassRef ref = authnContextClassRefBuilder.buildObject();
- authnCtx.setAuthnContextClassRef(ref);
- return authnCtx;
- }
- }
- }
- }
-
- // if no AuthnContextClassRef's matched, try the DeclRefs
- if (authnDeclRefs != null) {
- for (AuthnContextDeclRef declRef : authnDeclRefs) {
- if (declRef != null) {
- String s = declRef.getAuthnContextDeclRef();
- if (s != null && authnMethod.equals((s))) {
- AuthnContextDeclRef ref = authnContextDeclRefBuilder.buildObject();
- authnCtx.setAuthnContextDeclRef(ref);
- return authnCtx;
- }
- }
- }
- }
-
- // no matches were found.
- return null;
- }
-
- /**
- * Verify the AuthnRequest is well-formed.
- *
- * @param authnRequest The user's SAML 2 AuthnRequest.
- * @param issuer The Issuer of the AuthnRequest.
- * @param relyingParty The relying party configuration for the request's originator.
- * @param session The user's HttpSession.
- *
- * @throws AuthenticationRequestException on error.
- */
- protected void verifyAuthnRequest(final AuthenticationRequestContext requestContext)
- throws AuthenticationRequestException {
-
- final AuthnRequest authnRequest = requestContext.getAuthnRequest();
- String issuer = requestContext.getIssuer();
- final RelyingPartyConfiguration relyingParty = requestContext.getRpConfig();
- final HttpSession session = requestContext.getHttpSession();
-
- Status failureStatus;
-
- // Check if we are in scope to handle this AuthnRequest
- checkScope(authnRequest, issuer);
-
- // verify that the AssertionConsumerService url is valid.
- verifyAssertionConsumerService(requestContext, getRelyingPartyConfigurationManager().getMetadataProvider());
-
- // check for nameID constraints.
- verifySubject(requestContext);
- }
-
- /**
- * Get and verify the Subject element.
- *
- * @param requestContext The context for the current request.
- *
- * @throws AuthenticationRequestException on error.
- */
- protected void verifySubject(final AuthenticationRequestContext requestContext)
- throws AuthenticationRequestException {
-
- final AuthnRequest authnRequest = requestContext.getAuthnRequest();
-
- Status failureStatus;
-
- Subject subject = authnRequest.getSubject();
-
- if (subject == null) {
- failureStatus = buildStatus(StatusCode.REQUESTER_URI, null, "SAML 2 AuthnRequest " + authnRequest.getID()
- + " is malformed: It does not contain a Subject.");
- throw new AuthenticationRequestException("AuthnRequest lacks a Subject", failureStatus);
- }
-
- // The Web Browser SSO profile disallows SubjectConfirmation
- // methods in the requested subject.
- List<SubjectConfirmation> confMethods = subject.getSubjectConfirmations();
- if (confMethods != null || confMethods.size() > 0) {
- log.error("SAML 2 AuthnRequest " + authnRequest.getID()
- + " is malformed: It contains SubjectConfirmation elements.");
- failureStatus = buildStatus(StatusCode.REQUESTER_URI, null, "SAML 2 AuthnRequest " + authnRequest.getID()
- + " is malformed: It contains SubjectConfirmation elements.");
- throw new AuthenticationRequestException("AuthnRequest contains SubjectConfirmation elements",
- failureStatus);
- }
-
- requestContext.setSubject(subject);
-
- return;
- }
-
- /**
- * Ensure that metadata can be found for the SP that issued the AuthnRequest.
- *
- * If found, the request context is updated to reflect the appropriate entries.
- *
- * Before this method may be called, the request context must have an issuer set.
- *
- * @param requestContext The context for the current request.
- *
- * @throws AuthenticationRequestException On error.
- */
- protected void validateRequestAgainstMetadata(final AuthenticationRequestContext requestContext)
- throws AuthenticationRequestException {
-
- RelyingPartyConfiguration relyingParty = null;
- SSOConfiguration ssoConfig = null;
- SPSSODescriptor spDescriptor = null;
-
- // check that we have metadata for the RP
- relyingParty = getRelyingPartyConfigurationManager().getRelyingPartyConfiguration(requestContext.getIssuer());
-
- ProfileConfiguration temp = relyingParty.getProfileConfigurations().get(SSOConfiguration.PROFILE_ID);
- if (temp == null) {
- log.error("SAML 2 Authentication Request: No profile configuration registered for "
- + SSOConfiguration.PROFILE_ID);
- throw new AuthenticationRequestException("No profile configuration registered for "
- + SSOConfiguration.PROFILE_ID);
- }
-
- ssoConfig = (SSOConfiguration) temp;
-
- try {
- spDescriptor = getMetadataProvider().getEntityDescriptor(relyingParty.getRelyingPartyId())
- .getSPSSODescriptor(SAML20_PROTOCOL_URI);
- } catch (MetadataProviderException ex) {
- log.error("SAML 2 Authentication Request: Unable to locate SPSSODescriptor for SP "
- + requestContext.getIssuer() + " for protocol " + SAML20_PROTOCOL_URI, ex);
-
- Status failureStatus = buildStatus(StatusCode.REQUESTER_URI, null, "No metadata available for "
- + relyingParty.getRelyingPartyId());
-
- throw new AuthenticationRequestException(
- "SAML 2 Authentication Request: Unable to locate SPSSODescriptor for SP "
- + requestContext.getIssuer() + " for protocol " + SAML20_PROTOCOL_URI, ex, failureStatus);
- }
-
- if (spDescriptor == null) {
- log.error("SAML 2 Authentication Request: Unable to locate SPSSODescriptor for SP "
- + requestContext.getIssuer() + " for protocol " + SAML20_PROTOCOL_URI);
-
- Status failureStatus = buildStatus(StatusCode.REQUESTER_URI, null, "No metadata available for "
- + relyingParty.getRelyingPartyId());
-
- throw new AuthenticationRequestException(
- "SAML 2 Authentication Request: Unable to locate SPSSODescriptor for SP "
- + requestContext.getIssuer() + " for protocol " + SAML20_PROTOCOL_URI, failureStatus);
- }
-
- // if all metadata was found, update the request context.
- requestContext.setRpConfig(relyingParty);
- requestContext.setSsoConfig(ssoConfig);
- requestContext.setSpDescriptor(spDescriptor);
- }
-
- /**
- * Return the endpoint URL and protocol binding to use for the AuthnRequest.
- *
- * @param requestContext The context for the current request.
- *
- * @param metadata The appropriate Metadata.
- *
- * @throws AuthenticationRequestException On error.
- */
- protected void verifyAssertionConsumerService(final AuthenticationRequestContext requestContext,
-
- final MetadataProvider metadata) throws AuthenticationRequestException {
-
- Status failureStatus;
-
- final AuthnRequest authnRequest = requestContext.getAuthnRequest();
- String providerId = requestContext.getRpConfig().getRelyingPartyId();
-
- // Either the AssertionConsumerServiceIndex must be present
- // or AssertionConsumerServiceURL must be present.
-
- Integer idx = authnRequest.getAssertionConsumerServiceIndex();
- String acsURL = authnRequest.getAssertionConsumerServiceURL();
-
- if (idx != null && acsURL != null) {
- log
- .error("SAML 2 AuthnRequest "
- + authnRequest.getID()
- + " is malformed: It contains both an AssertionConsumerServiceIndex and an AssertionConsumerServiceURL");
- failureStatus = buildStatus(
- StatusCode.REQUESTER_URI,
- null,
- "SAML 2 AuthnRequest "
- + authnRequest.getID()
- + " is malformed: It contains both an AssertionConsumerServiceIndex and an AssertionConsumerServiceURL");
- throw new AuthenticationRequestException("Malformed AuthnRequest", failureStatus);
- }
-
- SPSSODescriptor spDescriptor;
- try {
- spDescriptor = metadata.getEntityDescriptor(providerId).getSPSSODescriptor(SAML20_PROTOCOL_URI);
- } catch (MetadataProviderException ex) {
- log.error("Unable retrieve SPSSODescriptor metadata for providerId " + providerId
- + " while processing SAML 2 AuthnRequest " + authnRequest.getID(), ex);
- failureStatus = buildStatus(StatusCode.RESPONDER_URI, null, "Unable to locate metadata for " + providerId);
- throw new AuthenticationRequestException("Unable to locate metadata", ex, failureStatus);
- }
-
- List<AssertionConsumerService> acsList = spDescriptor.getAssertionConsumerServices();
-
- // if the ACS index is specified, retrieve it from the metadata
- if (idx != null) {
-
- int i = idx.intValue();
-
- // if the index is out of range, return an appropriate error.
- if (i > acsList.size()) {
- log.error("Illegal AssertionConsumerIndex specicifed (" + i + ") in SAML 2 AuthnRequest "
- + authnRequest.getID());
-
- failureStatus = buildStatus(StatusCode.REQUESTER_URI, null,
- "Illegal AssertionConsumerIndex specicifed (" + i + ") in SAML 2 AuthnRequest "
- + authnRequest.getID());
-
- throw new AuthenticationRequestException("Illegal AssertionConsumerIndex in AuthnRequest",
- failureStatus);
- }
-
- requestContext.setAssertionConsumerService(acsList.get(i));
- return;
- }
-
- // if the ACS endpoint is specified, validate it against the metadata
- String protocolBinding = authnRequest.getProtocolBinding();
- for (AssertionConsumerService acs : acsList) {
- if (acsURL.equals(acs.getLocation())) {
- if (protocolBinding != null) {
- if (protocolBinding.equals(acs.getBinding())) {
- requestContext.setAssertionConsumerService(acs);
- return;
- }
- }
- }
- }
-
- log.error("Error processing SAML 2 AuthnRequest message " + authnRequest.getID()
- + ": Unable to validate AssertionConsumerServiceURL against metadata: " + acsURL + " for binding "
- + protocolBinding);
-
- failureStatus = buildStatus(StatusCode.REQUESTER_URI, null,
- "Unable to validate AssertionConsumerService against metadata.");
-
- throw new AuthenticationRequestException(
- "SAML 2 AuthenticationRequest: Unable to validate AssertionConsumerService against Metadata",
- failureStatus);
- }
-
- /**
- * Check if an {@link AuthnRequest} contains a {@link Scoping} element. If so, check if the specified IdP is in the
- * {@link IDPList} element. If no Scoping element is present, this method returns <code>true</code>.
- *
- * @param authnRequest The {@link AuthnRequest} element to check.
- * @param providerId The IdP's ProviderID.
- *
- * @throws AuthenticationRequestException on error.
- */
- protected void checkScope(final AuthnRequest authnRequest, String providerId) throws AuthenticationRequestException {
-
- Status failureStatus;
-
- List<String> idpEntries = new LinkedList<String>();
-
- Scoping scoping = authnRequest.getScoping();
- if (scoping == null) {
- return;
- }
-
- // process all of the explicitly listed idp provider ids
- IDPList idpList = scoping.getIDPList();
- if (idpList == null) {
- return;
- }
-
- List<IDPEntry> explicitIDPEntries = idpList.getIDPEntrys();
- if (explicitIDPEntries != null) {
- for (IDPEntry entry : explicitIDPEntries) {
- String s = entry.getProviderID();
- if (s != null) {
- idpEntries.add(s);
- }
- }
- }
-
- // If the IDPList is incomplete, retrieve the complete list
- // and add the entries to idpEntries.
- GetComplete getComplete = idpList.getGetComplete();
- IDPList referencedIdPs = getCompleteIDPList(getComplete);
- if (referencedIdPs != null) {
- List<IDPEntry> referencedIDPEntries = referencedIdPs.getIDPEntrys();
- if (referencedIDPEntries != null) {
- for (IDPEntry entry : referencedIDPEntries) {
- String s = entry.getProviderID();
- if (s != null) {
- idpEntries.add(s);
- }
- }
- }
- }
-
- // iterate over all the IDPEntries we've gathered,
- // and check if we're in scope.
- for (String requestProviderId : idpEntries) {
- if (providerId.equals(requestProviderId)) {
- log.debug("Found Scoping match for IdP: (" + providerId + ")");
- return;
- }
- }
-
- log.error("SAML 2 AuthnRequest " + authnRequest.getID() + " contains a Scoping element which "
- + "does not contain a providerID registered with this IdP.");
-
- failureStatus = buildStatus(StatusCode.RESPONDER_URI, StatusCode.NO_SUPPORTED_IDP_URI, null);
- throw new AuthenticationRequestException("Unrecognized providerID in Scoping element", failureStatus);
- }
-
- /**
- * Retrieve an incomplete IDPlist.
- *
- * This only handles URL-based <GetComplete/> references.
- *
- * @param getComplete The (possibly <code>null</code>) <GetComplete/> element
- *
- * @return an {@link IDPList} or <code>null</code> if the uri can't be dereferenced.
- */
- protected IDPList getCompleteIDPList(final GetComplete getComplete) {
-
- // XXX: enhance this method to cache the url and last-modified-header
-
- if (getComplete == null) {
- return null;
- }
-
- String uri = getComplete.getGetComplete();
- if (uri != null) {
- return null;
- }
-
- IDPList idpList = null;
- InputStream istream = null;
-
- try {
- URL url = new URL(uri);
- URLConnection conn = url.openConnection();
- istream = conn.getInputStream();
-
- // convert the raw data into an XML object
- Document doc = parserPool.parse(istream);
- Element docElement = doc.getDocumentElement();
- Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(docElement);
- idpList = (IDPList) unmarshaller.unmarshall(docElement);
-
- } catch (MalformedURLException ex) {
- log.error("Unable to retrieve GetComplete IDPList. Unsupported URI: " + uri, ex);
- } catch (IOException ex) {
- log.error("IO Error while retreieving GetComplete IDPList from " + uri, ex);
- } catch (XMLParserException ex) {
- log.error("Internal OpenSAML error while parsing GetComplete IDPList from " + uri, ex);
- } catch (UnmarshallingException ex) {
- log.error("Internal OpenSAML error while unmarshalling GetComplete IDPList from " + uri, ex);
- } finally {
-
- if (istream != null) {
- try {
- istream.close();
- } catch (IOException ex) {
- // pass
- }
- }
- }
-
- return idpList;
- }
-
- /**
- * Encode a SAML Response.
- *
- * @param binding The SAML protocol binding to use.
- * @param requestContext The context for the request.
- *
- * @throws ProfileException On error.
- */
- protected void encodeResponse(String binding, final AuthenticationRequestContext requestContext)
- throws ProfileException {
-
- final ProfileResponse<ServletResponse> profileResponse = requestContext.getProfileResponse();
- final Response samlResponse = requestContext.getResponse();
- final RelyingPartyConfiguration relyingParty = requestContext.getRpConfig();
- final RoleDescriptor roleDescriptor = requestContext.getSpDescriptor();
- final Endpoint endpoint = requestContext.getAssertionConsumerService();
-
- MessageEncoder<ServletResponse> encoder = getMessageEncoderFactory().getMessageEncoder(binding);
- if (encoder == null) {
- log.error("No MessageEncoder registered for " + binding);
- throw new ProfileException("No MessageEncoder registered for " + binding);
- }
-
- encoder.setResponse(profileResponse.getRawResponse());
- encoder.setIssuer(relyingParty.getProviderId());
- encoder.setMetadataProvider(getRelyingPartyConfigurationManager().getMetadataProvider());
- encoder.setRelyingPartyRole(roleDescriptor);
- encoder.setSigningCredential(relyingParty.getDefaultSigningCredential());
- encoder.setSamlMessage(samlResponse);
- encoder.setRelyingPartyEndpoint(endpoint);
-
- try {
- encoder.encode();
- } catch (BindingException ex) {
- log.error("Unable to encode response the relying party: " + relyingParty.getRelyingPartyId(), ex);
- throw new ProfileException("Unable to encode response the relying party: "
- + relyingParty.getRelyingPartyId(), ex);
- }
-
- }
-
-}
import org.opensaml.log.Level;
import org.opensaml.saml2.core.Advice;
import org.opensaml.saml2.core.Assertion;
+import org.opensaml.saml2.core.AttributeQuery;
+import org.opensaml.saml2.core.AttributeStatement;
import org.opensaml.saml2.core.Audience;
import org.opensaml.saml2.core.AudienceRestriction;
import org.opensaml.saml2.core.AuthnRequest;
import edu.internet2.middleware.shibboleth.common.attribute.BaseAttribute;
import edu.internet2.middleware.shibboleth.common.attribute.encoding.AttributeEncoder;
import edu.internet2.middleware.shibboleth.common.attribute.encoding.AttributeEncodingException;
+import edu.internet2.middleware.shibboleth.common.attribute.provider.SAML2AttributeAuthority;
+import edu.internet2.middleware.shibboleth.common.attribute.provider.ShibbolethSAMLAttributeRequestContext;
import edu.internet2.middleware.shibboleth.common.log.AuditLogEntry;
import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml2.AbstractSAML2ProfileConfiguration;
import edu.internet2.middleware.shibboleth.idp.profile.AbstractSAMLProfileHandler;
+import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
+import edu.internet2.middleware.shibboleth.idp.session.Session;
/**
* Common implementation details for profile handlers.
* @return the built response
*
* @throws ProfileException thrown if there is a problem creating the SAML response
- * @throws AttributeRequestException thrown if there is a problem resolving attributes
*/
protected Response buildResponse(SAML2ProfileRequestContext requestContext, Subject assertionSubject,
- List<Statement> statements) throws ProfileException, AttributeRequestException {
+ List<Statement> statements) throws ProfileException {
DateTime issueInstant = new DateTime();
}
/**
+ * Executes a query for attributes and builds a SAML attribute statement from the results.
+ *
+ * @param requestContext current request context
+ *
+ * @return attribute statement resulting from the query
+ *
+ * @throws ProfileException thrown if there is a problem making the query
+ */
+ protected AttributeStatement buildAttributeStatement(SAML2ProfileRequestContext requestContext)
+ throws ProfileException {
+
+ if (log.isDebugEnabled()) {
+ log.debug("Creating attribute statement in response to SAML request "
+ + requestContext.getSamlRequest().getID() + " from relying party "
+ + requestContext.getRelyingPartyId());
+ }
+
+ AbstractSAML2ProfileConfiguration profileConfiguration = requestContext.getProfileConfiguration();
+ SAML2AttributeAuthority attributeAuthority = profileConfiguration.getAttributeAuthority();
+
+ if (log.isDebugEnabled()) {
+ log.debug("Resolving principal name for subject of SAML request " + requestContext.getSamlRequest().getID()
+ + " from relying party " + requestContext.getRelyingPartyId());
+ }
+
+ try {
+ if (log.isDebugEnabled()) {
+ log.debug("Resolving attributes for principal " + requestContext.getPrincipalName()
+ + " of SAML request " + requestContext.getSamlRequest().getID() + " from relying party "
+ + requestContext.getRelyingPartyId());
+ }
+ Map<String, BaseAttribute> principalAttributes = attributeAuthority
+ .getAttributes(buildAttributeRequestContext(requestContext));
+
+ requestContext.setPrincipalAttributes(principalAttributes);
+
+ if (requestContext.getSamlRequest() instanceof AttributeQuery) {
+ return attributeAuthority.buildAttributeStatement((AttributeQuery) requestContext.getSamlRequest(),
+ principalAttributes.values());
+ } else {
+ return attributeAuthority.buildAttributeStatement(null, principalAttributes.values());
+ }
+ } catch (AttributeRequestException e) {
+ log.error("Error resolving attributes for SAML request " + requestContext.getSamlRequest().getID()
+ + " from relying party " + requestContext.getRelyingPartyId(), e);
+ requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, null, "Error resolving attributes"));
+ throw new ProfileException("Error resolving attributes for SAML request "
+ + requestContext.getSamlRequest().getID() + " from relying party "
+ + requestContext.getRelyingPartyId(), e);
+ }
+ }
+
+ /**
+ * Resolves the principal name of the subject of the request.
+ *
+ * @param requestContext current request context
+ *
+ * @throws ProfileException thrown if the principal name can not be resolved
+ */
+ protected void resolvePrincipal(SAML2ProfileRequestContext requestContext) throws ProfileException {
+ AbstractSAML2ProfileConfiguration profileConfiguration = requestContext.getProfileConfiguration();
+ SAML2AttributeAuthority attributeAuthority = profileConfiguration.getAttributeAuthority();
+
+ if (log.isDebugEnabled()) {
+ log.debug("Resolving principal name for subject of SAML request " + requestContext.getSamlRequest().getID()
+ + " from relying party " + requestContext.getRelyingPartyId());
+ }
+
+ try {
+ String principal = attributeAuthority.getPrincipal(buildAttributeRequestContext(requestContext));
+ requestContext.setPrincipalName(principal);
+ } catch (AttributeRequestException e) {
+ log.error("Error resolving attributes for SAML request " + requestContext.getSamlRequest().getID()
+ + " from relying party " + requestContext.getRelyingPartyId(), e);
+ requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, StatusCode.UNKNOWN_PRINCIPAL_URI,
+ "Error resolving principal"));
+ throw new ProfileException("Error resolving attributes for SAML request "
+ + requestContext.getSamlRequest().getID() + " from relying party "
+ + requestContext.getRelyingPartyId(), e);
+ }
+ }
+
+ /**
+ * Creates an attribute query context from the current profile request context.
+ *
+ * @param requestContext current profile request
+ *
+ * @return created query context
+ */
+ protected ShibbolethSAMLAttributeRequestContext<NameID, AttributeQuery> buildAttributeRequestContext(
+ SAML2ProfileRequestContext requestContext) {
+
+ ShibbolethSAMLAttributeRequestContext<NameID, AttributeQuery> queryContext;
+ if (requestContext.getSamlRequest() instanceof AttributeQuery) {
+ queryContext = new ShibbolethSAMLAttributeRequestContext<NameID, AttributeQuery>(getMetadataProvider(),
+ requestContext.getRelyingPartyConfiguration(), (AttributeQuery) requestContext.getSamlRequest());
+ } else {
+ queryContext = new ShibbolethSAMLAttributeRequestContext<NameID, AttributeQuery>(getMetadataProvider(),
+ requestContext.getRelyingPartyConfiguration());
+ }
+
+ queryContext.setAttributeRequester(requestContext.getAssertingPartyId());
+ queryContext.setPrincipalName(requestContext.getPrincipalName());
+ queryContext.setProfileConfiguration(requestContext.getProfileConfiguration());
+ queryContext.setRequest(requestContext.getProfileRequest());
+
+ Session userSession = getSessionManager().getSession(getUserSessionId(requestContext.getProfileRequest()));
+ if (userSession != null) {
+ queryContext.setUserSession(userSession);
+ ServiceInformation serviceInfo = userSession.getServiceInformation(requestContext.getRelyingPartyId());
+ if (serviceInfo != null) {
+ String principalAuthenticationMethod = serviceInfo.getAuthenticationMethod().getAuthenticationMethod();
+
+ requestContext.setPrincipalAuthenticationMethod(principalAuthenticationMethod);
+ queryContext.setPrincipalAuthenticationMethod(principalAuthenticationMethod);
+ }
+ }
+
+ return queryContext;
+ }
+
+ /**
* Signs the given assertion if either the current profile configuration or the relying party configuration contains
* signing credentials.
*
* @param topLevelCode The top-level status code. Should be from saml-core-2.0-os, sec. 3.2.2.2
* @param secondLevelCode An optional second-level failure code. Should be from saml-core-2.0-is, sec 3.2.2.2. If
* null, no second-level Status element will be set.
- * @param secondLevelFailureMessage An optional second-level failure message
+ * @param failureMessage An optional second-level failure message
*
* @return a Status object.
*/
- protected Status buildStatus(String topLevelCode, String secondLevelCode, String secondLevelFailureMessage) {
+ protected Status buildStatus(String topLevelCode, String secondLevelCode, String failureMessage) {
Status status = getStatusBuilder().buildObject();
StatusCode statusCode = getStatusCodeBuilder().buildObject();
statusCode.setStatusCode(secondLevelStatusCode);
}
- if (secondLevelFailureMessage != null) {
+ if (failureMessage != null) {
StatusMessage msg = getStatusMessageBuilder().buildObject();
- msg.setMessage(secondLevelFailureMessage);
+ msg.setMessage(failureMessage);
status.setStatusMessage(msg);
}
}
}
} catch (AttributeEncodingException e) {
+ requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, null,
+ "Unable to construct NameID"));
throw new ProfileException("Unable to encode NameID attribute", e);
}
}
+ requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, StatusCode.INVALID_NAMEID_POLICY_URI,
+ "Unable to construct NameID"));
throw new ProfileException("No principal attributes support NameID construction");
}
if (assertingPartySupportedFormats.contains(nameFormat)) {
nameFormats.add(nameFormat);
} else {
+ requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI,
+ StatusCode.INVALID_NAMEID_POLICY_URI, "Format not supported: " + nameFormat));
throw new ProfileException("NameID format required by relying party is not supported");
}
}
return nameFormats;
} catch (MetadataProviderException e) {
+ requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, null,
+ "Unable to lookup entity metadata"));
throw new ProfileException("Unable to determine lookup entity metadata", e);
}
}
* Constructs an SAML response message carrying a request error.
*
* @param requestContext current request context
- * @param topLevelCode The top-level status code. Should be from saml-core-2.0-os, sec. 3.2.2.2
- * @param secondLevelCode An optional second-level failure code. Should be from saml-core-2.0-is, sec 3.2.2.2. If
- * null, no second-level Status element will be set.
- * @param secondLevelFailureMessage An optional second-level failure message
*
* @return the constructed error response
*/
- protected Response buildErrorResponse(SAML2ProfileRequestContext requestContext, String topLevelCode,
- String secondLevelCode, String secondLevelFailureMessage) {
+ protected Response buildErrorResponse(SAML2ProfileRequestContext requestContext) {
Response samlResponse = getResponseBuilder().buildObject();
samlResponse.setIssueInstant(new DateTime());
populateStatusResponse(requestContext, samlResponse);
- Status status = buildStatus(topLevelCode, secondLevelCode, secondLevelFailureMessage);
- samlResponse.setStatus(status);
+ samlResponse.setStatus(requestContext.getFailureStatus());
return samlResponse;
}
/** The NameID of the subject of this request. */
private NameID subjectNameID;
+ /** The request failure status. */
+ private Status failureStatus;
+
/**
* Constructor.
*
public void setSamlResponse(ResponseType response) {
samlResponse = response;
}
+
+ /**
+ * Gets the status reflecting a request failure.
+ *
+ * @return status reflecting a request failure
+ */
+ public Status getFailureStatus() {
+ return failureStatus;
+ }
+
+ /**
+ * Sets the status reflecting a request failure.
+ *
+ * @param status status reflecting a request failure
+ */
+ public void setFailureStatus(Status status) {
+ failureStatus = status;
+ }
}
}
\ No newline at end of file
// create the SAML response
samlResponse = buildResponse(requestContext, assertionSubject, statements);
- } catch (SecurityPolicyException e) {
- samlResponse = buildErrorResponse(requestContext, StatusCode.REQUESTER_URI, StatusCode.REQUEST_DENIED_URI,
- e.getMessage());
- } catch (AttributeRequestException e) {
- samlResponse = buildErrorResponse(requestContext, StatusCode.RESPONDER_URI,
- StatusCode.INVALID_ATTR_NAME_VALUE_URI, e.getMessage());
} catch (ProfileException e) {
- samlResponse = buildErrorResponse(requestContext, StatusCode.RESPONDER_URI, StatusCode.REQUEST_DENIED_URI,
- e.getMessage());
+ samlResponse = buildErrorResponse(requestContext);
}
requestContext.setSamlResponse(samlResponse);
* @param requestContext request context contianing the request to decode
*
* @throws ProfileException throw if there is a problem decoding the request
- * @throws SecurityPolicyException thrown if the message was decoded properly but did not meet the necessary
- * security policy requirements
*/
- protected void decodeRequest(AttributeQueryContext requestContext) throws ProfileException, SecurityPolicyException {
+ protected void decodeRequest(AttributeQueryContext requestContext) throws ProfileException {
if (log.isDebugEnabled()) {
log.debug("Decoding incomming request");
}
}
} catch (BindingException e) {
log.error("Error decoding attribute query message", e);
+ requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, null, "Error decoding message"));
throw new ProfileException("Error decoding attribute query message");
+ } catch (SecurityPolicyException e) {
+ log.error("Message did not meet security policy requirements", e);
+ requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, StatusCode.REQUEST_DENIED_URI,
+ "Message did not meet security policy requirements"));
+ throw new ProfileException("Message did not meet security policy requirements", e);
} finally {
// Set as much information as can be retrieved from the decoded message
SAMLSecurityPolicy securityPolicy = requestContext.getMessageDecoder().getSecurityPolicy();
}
/**
- * Executes a query for attributes and builds a SAML attribute statement from the results.
- *
- * @param requestContext current request context
- *
- * @return attribute statement resulting from the query
- *
- * @throws ProfileException thrown if there is a problem making the query
- * @throws AttributeRequestException thrown if there is a problem resolving attributes
- */
- protected AttributeStatement buildAttributeStatement(AttributeQueryContext requestContext) throws ProfileException,
- AttributeRequestException {
-
- if (log.isDebugEnabled()) {
- log.debug("Creating attribute statement in response to SAML request "
- + requestContext.getSamlRequest().getID() + " from relying party "
- + requestContext.getRelyingPartyId());
- }
-
- try {
- AttributeQueryConfiguration profileConfiguration = requestContext.getProfileConfiguration();
- if (profileConfiguration == null) {
- log.error("No SAML 2 attribute query profile configuration is defined for relying party: "
- + requestContext.getRelyingPartyId());
- throw new AttributeRequestException("SAML 2 attribute query is not configured for this relying party");
- }
-
- SAML2AttributeAuthority attributeAuthority = profileConfiguration.getAttributeAuthority();
-
- ShibbolethSAMLAttributeRequestContext<NameID, AttributeQuery> attributeRequestContext = buildAttributeRequestContext(requestContext);
-
- if (log.isDebugEnabled()) {
- log.debug("Resolving principal name for subject of SAML request "
- + requestContext.getSamlRequest().getID() + " from relying party "
- + requestContext.getRelyingPartyId());
- }
- String principal = attributeAuthority.getPrincipal(attributeRequestContext);
- requestContext.setPrincipalName(principal);
-
- if (log.isDebugEnabled()) {
- log.debug("Resolving attributes for principal " + principal + " of SAML request "
- + requestContext.getSamlRequest().getID() + " from relying party "
- + requestContext.getRelyingPartyId());
- }
- Map<String, BaseAttribute> principalAttributes = attributeAuthority
- .getAttributes(buildAttributeRequestContext(requestContext));
-
- requestContext.setPrincipalAttributes(principalAttributes);
-
- return attributeAuthority.buildAttributeStatement(requestContext.getSamlRequest(), principalAttributes
- .values());
- } catch (AttributeRequestException e) {
- log.error("Error resolving attributes for SAML request " + requestContext.getSamlRequest().getID()
- + " from relying party " + requestContext.getRelyingPartyId(), e);
- throw e;
- }
- }
-
- /**
- * Creates an attribute query context from the current profile request context.
- *
- * @param requestContext current profile request
- *
- * @return created query context
- */
- protected ShibbolethSAMLAttributeRequestContext<NameID, AttributeQuery> buildAttributeRequestContext(
- AttributeQueryContext requestContext) {
-
- ShibbolethSAMLAttributeRequestContext<NameID, AttributeQuery> queryContext = new ShibbolethSAMLAttributeRequestContext<NameID, AttributeQuery>(
- getMetadataProvider(), requestContext.getRelyingPartyConfiguration(), requestContext.getSamlRequest());
-
- queryContext.setAttributeRequester(requestContext.getAssertingPartyId());
- queryContext.setPrincipalName(requestContext.getPrincipalName());
- queryContext.setProfileConfiguration(requestContext.getProfileConfiguration());
- queryContext.setRequest(requestContext.getProfileRequest());
-
- Session userSession = getSessionManager().getSession(getUserSessionId(requestContext.getProfileRequest()));
- if (userSession != null) {
- queryContext.setUserSession(userSession);
- ServiceInformation serviceInfo = userSession.getServiceInformation(requestContext.getRelyingPartyId());
- if (serviceInfo != null) {
- String principalAuthenticationMethod = serviceInfo.getAuthenticationMethod().getAuthenticationMethod();
-
- requestContext.setPrincipalAuthenticationMethod(principalAuthenticationMethod);
- queryContext.setPrincipalAuthenticationMethod(principalAuthenticationMethod);
- }
- }
-
- return queryContext;
- }
-
- /**
* Encodes the request's SAML response and writes it to the servlet response.
*
* @param requestContext current request context
+++ /dev/null
-/*
- * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
- *
- * 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 edu.internet2.middleware.shibboleth.idp.profile.saml2;
-
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-
-import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
-import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
-import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
-
-import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
-
-import org.apache.log4j.Logger;
-import org.joda.time.DateTime;
-import org.opensaml.common.SAMLObject;
-import org.opensaml.common.binding.BindingException;
-import org.opensaml.common.binding.decoding.MessageDecoder;
-import org.opensaml.saml2.core.AuthnRequest;
-import org.opensaml.saml2.core.Response;
-import org.opensaml.ws.security.SecurityPolicyException;
-
-/**
- * Browser POST binding for SAML 2 AuthenticationRequest.
- */
-public class AuthenticationRequestBrowserPost extends AbstractAuthenticationRequest {
-
- /** Class logger. */
- private static final Logger log = Logger.getLogger(AuthenticationRequestBrowserPost.class);
-
- /** SAML 2 Profile ID. */
- protected static final String PROFILE_ID = "urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser";
-
- /** SAML 2 Binding URI. */
- protected static final String BINDING_URI = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";
-
- /** SubjectConfirmation method for Web Browser SSO profile. */
- protected static final String SUBJ_CONF_METHOD_URI = "urn:oasis:namurn:oasis:names:tc:SAML:2.0:cm:bearer";
-
- /** Constructor. */
- public AuthenticationRequestBrowserPost() {
- super();
- }
-
- /** {@inheritDoc} */
- public String getProfileId() {
- return PROFILE_ID;
- }
-
- /** {@inheritDoc} */
- public void processRequest(final ProfileRequest<ServletRequest> request,
- final ProfileResponse<ServletResponse> response)
- throws ProfileException {
-
- // Only http servlets are supported for now.
- if (!(request.getRawRequest() instanceof HttpServletRequest)) {
- log.error("Received a non-HTTP request");
- throw new ProfileException("Received a non-HTTP request");
- }
-
- // This method is called twice.
- // On the first time, there will be no AuthenticationRequestContext object. We redirect control to the
- // AuthenticationManager to authenticate the user. The AuthenticationManager then redirects control
- // back to this servlet. On the "return leg" connection, there will be a AuthenticationRequestContext object.
-
- HttpServletRequest req = (HttpServletRequest) request.getRawRequest();
- Object o = req.getSession().getAttribute(REQUEST_CONTEXT_SESSION_KEY);
- if (o != null && !(o instanceof AuthenticationRequestContext)) {
- log.error("SAML 2 AuthnRequest: Invalid session data found for AuthenticationRequestContext");
- throw new ProfileException("SAML 2 AuthnRequest: Invalid session data found for AuthenticationRequestContext");
- }
-
- if (o == null) {
- setupNewRequest(request, response);
- } else {
-
- AuthenticationRequestContext requestContext = (AuthenticationRequestContext)o;
-
- // clean up the HttpSession.
- requestContext.getHttpSession().removeAttribute(REQUEST_CONTEXT_SESSION_KEY);
- requestContext.getHttpSession().removeAttribute(LoginContext.LOGIN_CONTEXT_KEY);
-
- finishProcessingRequest(requestContext);
- }
- }
-
- /**
- * Begin processing a SAML 2.0 AuthnRequest.
- *
- * This ensures that the request is well-formed and that
- * appropriate metadata can be found for the SP.
- * Once these conditions are met, control is passed to
- * the AuthenticationManager to authenticate the user.
- *
- * @param request The ProfileRequest.
- * @param response The ProfileResponse
- *
- * @throws ProfileException On error.
- */
- protected void setupNewRequest(final ProfileRequest<ServletRequest> request,
- final ProfileResponse<ServletResponse> response) throws ProfileException {
-
- // If the user hasn't been authenticated, validate the AuthnRequest
- // and redirect to AuthenticationManager to authenticate the user.
-
- AuthenticationRequestContext requestContext = new AuthenticationRequestContext();
-
- requestContext.setProfileRequest(request);
- requestContext.setProfileResponse(response);
-
- try {
- // decode the AuthnRequest
- MessageDecoder<ServletRequest> decoder = getMessageDecoderFactory().getMessageDecoder(BINDING_URI);
- if (decoder == null) {
- log.error("SAML 2 AuthnRequest: No MessageDecoder registered for " + BINDING_URI);
- throw new ProfileException("SAML 2 AuthnRequest: No MessageDecoder registered for " + BINDING_URI);
- }
-
- decoder.setMetadataProvider(getMetadataProvider());
- populateMessageDecoder(decoder);
- decoder.decode();
-
- SAMLObject samlObject = decoder.getSAMLMessage();
- if (!(samlObject instanceof AuthnRequest)) {
- log.error("SAML 2 AuthnRequest: Received message is not a SAML 2 Authentication Request");
- throw new ProfileException("SAML 2 AuthnRequest: Received message is not a SAML 2 Authentication Request");
- }
-
- requestContext.setAuthnRequest((AuthnRequest) samlObject);
- requestContext.setIssuer(decoder.getSecurityPolicy().getIssuer());
- validateRequestAgainstMetadata(requestContext);
- verifyAuthnRequest(requestContext);
- authenticateUser(requestContext);
-
- } catch (BindingException ex) {
- log.error("SAML 2 Authentication Request: Unable to decode SAML 2 Authentication Request", ex);
- throw new ProfileException(
- "SAML 2 Authentication Request: Unable to decode SAML 2 Authentication Request", ex);
- } catch (SecurityPolicyException ex) {
- log.error("SAML 2 Authentication Request: Security error while decoding SAML 2 Authentication Request", ex);
- } catch (AuthenticationRequestException ex) {
-
- // AuthN failed. Send the failure status.
- requestContext.setResponse(buildResponse(requestContext.getAuthnRequest().getID(),
- new DateTime(), requestContext.getIssuer(), ex.getStatus()));
- encodeResponse(BINDING_URI, requestContext);
- }
- }
-
- /**
- * Process the "return leg" of a SAML 2 Authentication Request.
- *
- * This evaluates the AuthenticationManager's LoginContext and generates an Authentication Assertion.
- *
- * @param requestContext The context for this request.
- *
- * @throws ProfileException On error.
- */
- protected void finishProcessingRequest(final AuthenticationRequestContext requestContext) throws ProfileException {
-
- // The user has already been authenticated,
- // so generate an AuthenticationStatement.
- evaluateRequest(requestContext);
- encodeResponse(BINDING_URI, requestContext);
- }
-
-}
package edu.internet2.middleware.shibboleth.idp.profile.saml2;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import org.apache.log4j.Logger;
+import org.opensaml.common.SAMLObjectBuilder;
+import org.opensaml.common.binding.BindingException;
+import org.opensaml.common.binding.decoding.MessageDecoder;
+import org.opensaml.common.binding.encoding.MessageEncoder;
+import org.opensaml.common.binding.security.SAMLSecurityPolicy;
+import org.opensaml.saml2.core.AuthnContext;
+import org.opensaml.saml2.core.AuthnContextClassRef;
+import org.opensaml.saml2.core.AuthnContextDeclRef;
import org.opensaml.saml2.core.AuthnRequest;
+import org.opensaml.saml2.core.AuthnStatement;
+import org.opensaml.saml2.core.RequestedAuthnContext;
import org.opensaml.saml2.core.Response;
+import org.opensaml.saml2.core.Statement;
+import org.opensaml.saml2.core.StatusCode;
+import org.opensaml.saml2.core.Subject;
+import org.opensaml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.ws.security.SecurityPolicyException;
+import org.opensaml.xml.io.MarshallingException;
+import org.opensaml.xml.io.UnmarshallingException;
import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
+import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml2.SSOConfiguration;
import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
+import edu.internet2.middleware.shibboleth.idp.authn.Saml2LoginContext;
/**
* SAML 2.0 authentication request profile handler.
*/
public class AuthenticationRequestProfileHandler extends AbstractSAML2ProfileHandler {
+ /** Class logger. */
+ private final Logger log = Logger.getLogger(AuthenticationRequestProfileHandler.class);
+
+ /** Builder of AuthnStatement objects. */
+ private SAMLObjectBuilder<AuthnStatement> authnStatementBuilder;
+
+ /** Builder of AuthnContext objects. */
+ private SAMLObjectBuilder<AuthnContext> authnContextBuilder;
+
+ /** Builder of AuthnContextClassRef objects. */
+ private SAMLObjectBuilder<AuthnContextClassRef> authnContextClassRefBuilder;
+
+ /** Builder of AuthnContextDeclRef objects. */
+ private SAMLObjectBuilder<AuthnContextDeclRef> authnContextDeclRefBuilder;
+
+ /** URL of the authentication manager servlet. */
+ private String authenticationManagerURL;
+
+ /** URI of request decoder. */
+ private String decodingBinding;
+
+ /** URI of response encoder. */
+ private String encodingBinding;
+
+ /**
+ * Constructor.
+ *
+ * @param decoder URI of the request decoder to use
+ * @param encoder URI of the response encoder to use
+ */
+ @SuppressWarnings("unchecked")
+ public AuthenticationRequestProfileHandler(String decoder, String encoder) {
+ super();
+
+ if (decoder == null || encoder == null) {
+ throw new IllegalArgumentException("Message decoding and encoding binding URI may not be null");
+ }
+
+ authnStatementBuilder = (SAMLObjectBuilder<AuthnStatement>) getBuilderFactory().getBuilder(
+ AuthnStatement.DEFAULT_ELEMENT_NAME);
+ authnContextBuilder = (SAMLObjectBuilder<AuthnContext>) getBuilderFactory().getBuilder(
+ AuthnContext.DEFAULT_ELEMENT_NAME);
+ authnContextClassRefBuilder = (SAMLObjectBuilder<AuthnContextClassRef>) getBuilderFactory().getBuilder(
+ AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
+ authnContextDeclRefBuilder = (SAMLObjectBuilder<AuthnContextDeclRef>) getBuilderFactory().getBuilder(
+ AuthnContextDeclRef.DEFAULT_ELEMENT_NAME);
+ }
+
/** {@inheritDoc} */
public String getProfileId() {
return "urn:mace:shibboleth:2.0:idp:profiles:saml2:request:authentication";
public void processRequest(ProfileRequest<ServletRequest> request, ProfileResponse<ServletResponse> response)
throws ProfileException {
+ HttpSession httpSession = ((HttpServletRequest) request.getRawRequest()).getSession(true);
+ if (httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY) == null) {
+ performAuthentication(request, response);
+ } else {
+ completeAuthenticationRequest(request, response);
+ }
+ }
+
+ /**
+ * Creates a {@link Saml2LoginContext} an sends the request off to the AuthenticationManager to begin the
+ * process of authenticating the user.
+ *
+ * @param request current request
+ * @param response current response
+ *
+ * @throws ProfileException thrown if there is a problem creating the login context and transferring control to the
+ * authentication manager
+ */
+ protected void performAuthentication(ProfileRequest<ServletRequest> request,
+ ProfileResponse<ServletResponse> response) throws ProfileException {
+ HttpServletRequest httpRequest = (HttpServletRequest) request.getRawRequest();
+
+ AuthnRequest authnRequest = null;
+ try {
+ MessageDecoder<ServletRequest> decoder = decodeRequest(request);
+ SAMLSecurityPolicy<ServletRequest> securityPolicy = decoder.getSecurityPolicy();
+
+ String relyingParty = securityPolicy.getIssuer();
+ authnRequest = (AuthnRequest) decoder.getSAMLMessage();
+
+ Saml2LoginContext loginContext = new Saml2LoginContext(relyingParty, authnRequest);
+ loginContext.setProfileHandlerURL(httpRequest.getRequestURI());
+
+ HttpSession httpSession = httpRequest.getSession();
+ httpSession.setAttribute(Saml2LoginContext.LOGIN_CONTEXT_KEY, loginContext);
+ RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(authenticationManagerURL);
+ dispatcher.forward(httpRequest, response.getRawResponse());
+ } catch (MarshallingException e) {
+ log.error("Unable to marshall authentication request context");
+ throw new ProfileException("Unable to marshall authentication request context", e);
+ } catch (IOException ex) {
+ log.error("Error forwarding SAML 2 AuthnRequest " + authnRequest.getID() + " to AuthenticationManager", ex);
+ throw new ProfileException("Error forwarding SAML 2 AuthnRequest " + authnRequest.getID()
+ + " to AuthenticationManager", ex);
+ } catch (ServletException ex) {
+ log.error("Error forwarding SAML 2 AuthnRequest " + authnRequest.getID() + " to AuthenticationManager", ex);
+ throw new ProfileException("Error forwarding SAML 2 AuthnRequest " + authnRequest.getID()
+ + " to AuthenticationManager", ex);
+ }
+ }
+
+ /**
+ * Creates a response to the {@link AuthnRequest} and sends the user, with response in tow, back to the relying
+ * party after they've been authenticated.
+ *
+ * @param request current request
+ * @param response current response
+ *
+ * @throws ProfileException thrown if the response can not be created and sent back to the relying party
+ */
+ protected void completeAuthenticationRequest(ProfileRequest<ServletRequest> request,
+ ProfileResponse<ServletResponse> response) throws ProfileException {
+
+ HttpSession httpSession = ((HttpServletRequest) request.getRawRequest()).getSession(true);
+ Saml2LoginContext loginContext = (Saml2LoginContext) httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
+ AuthenticationRequestContext requestContext = buildRequestContext(loginContext, request, response);
+
+ Response samlResponse;
+ try {
+ if (!loginContext.getAuthenticationOK()) {
+ requestContext
+ .setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, StatusCode.AUTHN_FAILED_URI, null));
+ throw new ProfileException("User failed authentication");
+ }
+
+ ArrayList<Statement> statements = new ArrayList<Statement>();
+ statements.add(buildAuthnStatement(requestContext));
+ statements.add(buildAttributeStatement(requestContext));
+
+ Subject assertionSubject = buildSubject(requestContext, "urn:oasis:names:tc:SAML:2.0:cm:bearer");
+
+ samlResponse = buildResponse(requestContext, assertionSubject, statements);
+ } catch (ProfileException e) {
+ samlResponse = buildErrorResponse(requestContext);
+ }
+
+ requestContext.setSamlResponse(samlResponse);
+ encodeResponse(requestContext);
+ writeAuditLogEntry(requestContext);
+ }
+
+ /**
+ * Creates an appropriate message decoder, populates it, and decodes the incoming request.
+ *
+ * @param request current request
+ *
+ * @return message decoder containing the decoded message and other stateful information
+ *
+ * @throws ProfileException thrown if the incomming message failed decoding
+ */
+ protected MessageDecoder<ServletRequest> decodeRequest(ProfileRequest<ServletRequest> request)
+ throws ProfileException {
+ MessageDecoder<ServletRequest> decoder = getMessageDecoderFactory().getMessageDecoder(decodingBinding);
+ if (decoder == null) {
+ log.error("No request decoder was registered for binding type: " + decodingBinding);
+ throw new ProfileException("No request decoder was registered for binding type: " + decodingBinding);
+ }
+
+ populateMessageDecoder(decoder);
+ decoder.setRequest(request.getRawRequest());
+ try {
+ decoder.decode();
+ return decoder;
+ } catch (BindingException e) {
+ log.error("Error decoding authentication request message", e);
+ throw new ProfileException("Error decoding authentication request message", e);
+ } catch (SecurityPolicyException e) {
+ log.error("Message did not meet security policy requirements", e);
+ throw new ProfileException("Message did not meet security policy requirements", e);
+ }
+ }
+
+ /**
+ * Creates an authentication request context from the current environmental information.
+ *
+ * @param loginContext current login context
+ * @param request current request
+ * @param response current response
+ *
+ * @return created authentication request context
+ *
+ * @throws ProfileException thrown if there is a problem creating the context
+ */
+ protected AuthenticationRequestContext buildRequestContext(Saml2LoginContext loginContext,
+ ProfileRequest<ServletRequest> request, ProfileResponse<ServletResponse> response) throws ProfileException {
+ AuthenticationRequestContext requestContext = new AuthenticationRequestContext(request, response);
+
+ try {
+ String relyingPartyId = loginContext.getRelyingPartyId();
+ AuthnRequest authnRequest = loginContext.getAuthenticationRequest();
+
+ requestContext.setRelyingPartyId(relyingPartyId);
+
+ RelyingPartyConfiguration rpConfig = getRelyingPartyConfiguration(relyingPartyId);
+ requestContext.setRelyingPartyConfiguration(rpConfig);
+
+ requestContext.setRelyingPartyRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+
+ requestContext.setAssertingPartyId(requestContext.getRelyingPartyConfiguration().getProviderId());
+
+ requestContext.setAssertingPartyRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
+
+ requestContext.setProfileConfiguration((SSOConfiguration) rpConfig
+ .getProfileConfiguration(SSOConfiguration.PROFILE_ID));
+
+ requestContext.setSamlRequest(authnRequest);
+
+ return requestContext;
+ } catch (UnmarshallingException e) {
+ log.error("Unable to unmarshall authentication request context");
+ requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, null,
+ "Error recovering request state"));
+ throw new ProfileException("Error recovering request state", e);
+ }
+ }
+
+ /**
+ * Creates an authentication statement for the current request.
+ *
+ * @param requestContext current request context
+ *
+ * @return constructed authentication statement
+ */
+ protected AuthnStatement buildAuthnStatement(AuthenticationRequestContext requestContext) {
+ Saml2LoginContext loginContext = requestContext.getLoginContext();
+
+ AuthnContext authnContext = buildAuthnContext(requestContext);
+
+ AuthnStatement statement = authnStatementBuilder.buildObject();
+ statement.setAuthnContext(authnContext);
+ statement.setAuthnInstant(loginContext.getAuthenticationInstant());
+
+ // TODO
+ statement.setSessionIndex(null);
+
+ if (loginContext.getAuthenticationDuration() > 0) {
+ statement.setSessionNotOnOrAfter(loginContext.getAuthenticationInstant().plus(
+ loginContext.getAuthenticationDuration()));
+ }
+
+ // TODO
+ statement.setSubjectLocality(null);
+
+ return statement;
+ }
+
+ /**
+ * Creates an {@link AuthnContext} for a succesful authentication request.
+ *
+ * @param requestContext current request
+ *
+ * @return the built authn context
+ */
+ protected AuthnContext buildAuthnContext(AuthenticationRequestContext requestContext) {
+ AuthnContext authnContext = authnContextBuilder.buildObject();
+
+ Saml2LoginContext loginContext = requestContext.getLoginContext();
+ AuthnRequest authnRequest = requestContext.getSamlRequest();
+ RequestedAuthnContext requestedAuthnContext = authnRequest.getRequestedAuthnContext();
+ if (requestedAuthnContext != null) {
+ if (requestedAuthnContext.getAuthnContextClassRefs() != null) {
+ for (AuthnContextClassRef classRef : requestedAuthnContext.getAuthnContextClassRefs()) {
+ if (classRef.getAuthnContextClassRef().equals(loginContext.getAuthenticationMethod())) {
+ AuthnContextClassRef ref = authnContextClassRefBuilder.buildObject();
+ ref.setAuthnContextClassRef(loginContext.getAuthenticationMethod());
+ authnContext.setAuthnContextClassRef(ref);
+ }
+ }
+ } else if (requestedAuthnContext.getAuthnContextDeclRefs() != null) {
+ for (AuthnContextDeclRef declRef : requestedAuthnContext.getAuthnContextDeclRefs()) {
+ if (declRef.getAuthnContextDeclRef().equals(loginContext.getAuthenticationMethod())) {
+ AuthnContextDeclRef ref = authnContextDeclRefBuilder.buildObject();
+ ref.setAuthnContextDeclRef(loginContext.getAuthenticationMethod());
+ authnContext.setAuthnContextDeclRef(ref);
+ }
+ }
+ }
+ } else {
+ AuthnContextDeclRef ref = authnContextDeclRefBuilder.buildObject();
+ ref.setAuthnContextDeclRef(loginContext.getAuthenticationMethod());
+ authnContext.setAuthnContextDeclRef(ref);
+ }
+
+ return authnContext;
+ }
+
+ /**
+ * Encodes the request's SAML response and writes it to the servlet response.
+ *
+ * @param requestContext current request context
+ *
+ * @throws ProfileException thrown if no message encoder is registered for this profiles binding
+ */
+ protected void encodeResponse(AuthenticationRequestContext requestContext) throws ProfileException {
+ if (log.isDebugEnabled()) {
+ log.debug("Encoding response to SAML request " + requestContext.getSamlRequest().getID()
+ + " from relying party " + requestContext.getRelyingPartyId());
+ }
+ MessageEncoder<ServletResponse> encoder = getMessageEncoderFactory().getMessageEncoder(encodingBinding);
+ if (encoder == null) {
+ log.error("No response encoder was registered for binding type: " + encodingBinding);
+ throw new ProfileException("No response encoder was registered for binding type: " + encodingBinding);
+ }
+
+ super.populateMessageEncoder(encoder);
+ encoder.setResponse(requestContext.getProfileResponse().getRawResponse());
+ encoder.setSamlMessage(requestContext.getSamlResponse());
+ requestContext.setMessageEncoder(encoder);
+
+ try {
+ encoder.encode();
+ } catch (BindingException e) {
+ throw new ProfileException("Unable to encode response to relying party: "
+ + requestContext.getRelyingPartyId(), e);
+ }
}
/**
protected class AuthenticationRequestContext extends
SAML2ProfileRequestContext<AuthnRequest, Response, SSOConfiguration> {
- /** The IdP's LoginContext. */
- private LoginContext loginContext;
+ /** Current login context. */
+ private Saml2LoginContext loginContext;
/**
* Constructor.
}
/**
- * Gets the login context for this request.
+ * Gets the current login context.
*
- * @return login context for this request
+ * @return current login context
*/
- public LoginContext getLoginContext() {
+ public Saml2LoginContext getLoginContext() {
return loginContext;
}
/**
- * Sets the login context for this request.
+ * Sets the current login context.
*
- * @param context login context for this request
+ * @param context current login context
*/
- public void setLoginContext(LoginContext context) {
+ public void setLoginContext(Saml2LoginContext context) {
loginContext = context;
}
}