import org.w3c.dom.Element;
-import edu.internet2.middleware.shibboleth.idp.profile.saml2.HTTPSOAPAttributeQuery;
+import edu.internet2.middleware.shibboleth.idp.profile.saml2.AttributeQueryProfileHandler;
/**
* Spring bean definition parser for {@link HTTPSOAPAttributeQuery} profile handlers.
/** {@inheritDoc} */
protected Class getBeanClass(Element arg0) {
- return HTTPSOAPAttributeQuery.class;
+ return AttributeQueryProfileHandler.class;
}
}
\ No newline at end of file
package edu.internet2.middleware.shibboleth.idp.profile;
import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
+import javax.xml.namespace.QName;
import org.apache.log4j.Logger;
import org.opensaml.common.IdentifierGenerator;
import org.opensaml.common.binding.decoding.MessageDecoderFactory;
import org.opensaml.common.binding.encoding.MessageEncoderFactory;
-import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
import org.opensaml.saml2.metadata.provider.MetadataProvider;
import edu.internet2.middleware.shibboleth.common.log.AuditLogEntry;
import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
import edu.internet2.middleware.shibboleth.common.profile.provider.AbstractShibbolethProfileHandler;
import edu.internet2.middleware.shibboleth.common.relyingparty.provider.SAMLMDRelyingPartyConfigurationManager;
import edu.internet2.middleware.shibboleth.idp.session.Session;
/** Constructor. */
protected AbstractSAMLProfileHandler() {
super();
- idGenerator = new SecureRandomIdentifierGenerator();
}
/**
public IdentifierGenerator getIdGenerator() {
return idGenerator;
}
+
+ /**
+ * Gets an ID generator which may be used for SAML assertions, requests, etc.
+ *
+ * @param generator an ID generator which may be used for SAML assertions, requests, etc
+ */
+ public void setIdGenerator(IdentifierGenerator generator){
+ idGenerator = generator;
+ }
/**
* Gets the factory used to build new message decoders.
return null;
}
+
+ /**
+ * Contextual object used to accumlate information as profile requests are being processed.
+ */
+ protected class SAMLProfileRequestContext extends ShibbolethProfileRequestContext {
+
+ /** Role descriptor name that the asserting party is operating in. */
+ private QName assertingPartyRole;
+
+ /** Role descriptor name that the relying party is operating in. */
+ private QName relyingPartyRole;
+
+ /**
+ * Constructor.
+ *
+ * @param request current profile request
+ * @param response current profile response
+ */
+ public SAMLProfileRequestContext(ProfileRequest<ServletRequest> request,
+ ProfileResponse<ServletResponse> response) {
+ super(request, response);
+ }
+
+ /**
+ * Gets the role descriptor name that the asserting party is operating in.
+ *
+ * @return role descriptor name that the asserting party is operating in
+ */
+ public QName getAssertingPartyRole() {
+ return assertingPartyRole;
+ }
+
+ /**
+ * Sets the role descriptor name that the asserting party is operating in.
+ *
+ * @param role role descriptor name that the asserting party is operating in
+ */
+ public void setAssertingPartyRole(QName role) {
+ assertingPartyRole = role;
+ }
+
+ /**
+ * Gets the role descriptor name that the relying party is operating in.
+ *
+ * @return role descriptor name that the relying party is operating in
+ */
+ public QName getRelyingPartyRole() {
+ return relyingPartyRole;
+ }
+
+ /**
+ * Sets the role descriptor name that the relying party is operating in.
+ *
+ * @param role role descriptor name that the relying party is operating in
+ */
+ public void setRelyingPartyRole(QName role) {
+ relyingPartyRole = role;
+ }
+ }
}
\ No newline at end of file
package edu.internet2.middleware.shibboleth.idp.profile.saml1;
+import java.security.NoSuchAlgorithmException;
+
import javax.servlet.ServletResponse;
import org.apache.log4j.Logger;
-import org.opensaml.Configuration;
import org.opensaml.common.SAMLObjectBuilder;
import org.opensaml.common.SAMLVersion;
import org.opensaml.common.binding.BindingException;
import org.opensaml.common.binding.encoding.MessageEncoder;
import org.opensaml.common.impl.SAMLObjectContentReference;
-import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
import org.opensaml.saml1.core.Assertion;
+import org.opensaml.saml1.core.Response;
import org.opensaml.saml1.core.Status;
import org.opensaml.saml1.core.StatusCode;
import org.opensaml.saml1.core.StatusMessage;
-import org.opensaml.saml1.core.Response;
-import org.opensaml.saml2.metadata.AssertionConsumerService;
import org.opensaml.saml2.metadata.Endpoint;
import org.opensaml.saml2.metadata.RoleDescriptor;
-import org.opensaml.saml2.metadata.provider.MetadataProvider;
import org.opensaml.xml.XMLObjectBuilder;
-import org.opensaml.xml.XMLObjectBuilderFactory;
import org.opensaml.xml.security.credential.Credential;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.Signer;
/** Class logger. */
private static Logger log = Logger.getLogger(AbstractSAML1ProfileHandler.class);
- /** For generating random ids. */
- private SecureRandomIdentifierGenerator idGenerator;
-
/** Builder for Status objects. */
protected SAMLObjectBuilder<Status> statusBuilder;
/**
* Default constructor.
*/
- public AbstractSAML1ProfileHandler() {
- idGenerator = new SecureRandomIdentifierGenerator();
-
+ @SuppressWarnings("unchecked")
+ public AbstractSAML1ProfileHandler(){
+ super();
statusBuilder = (SAMLObjectBuilder<Status>) getBuilderFactory().getBuilder(Status.DEFAULT_ELEMENT_NAME);
statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory().getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
statusMessageBuilder = (SAMLObjectBuilder<StatusMessage>) getBuilderFactory().getBuilder(StatusMessage.DEFAULT_ELEMENT_NAME);
}
/**
- * Returns the id generator.
- *
- * @return Returns the idGenerator.
- */
- public SecureRandomIdentifierGenerator getIdGenerator() {
- return idGenerator;
- }
-
- /**
* Build a SAML 1 Status element.
*
* @param statusCode The status code - see oasis-sstc-saml-core-1.1, section 3.4.3.1.
Subject subject = subjectBuilder.buildObject();
NameIdentifier nameID = nameIdentifierBuilder.buildObject();
- nameID.setFormat(ssoConfig.getDefaultNameIDFormat());
+ nameID.setFormat(ssoConfig.getSubjectNameFormat());
String username = loginContext.getUserID();
+++ /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 javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-import org.apache.log4j.Logger;
-import org.joda.time.DateTime;
-import org.opensaml.common.binding.BindingException;
-import org.opensaml.common.binding.decoding.MessageDecoder;
-import org.opensaml.common.binding.encoding.MessageEncoder;
-import org.opensaml.log.Level;
-import org.opensaml.saml2.core.Assertion;
-import org.opensaml.saml2.core.AttributeQuery;
-import org.opensaml.saml2.core.AttributeStatement;
-import org.opensaml.saml2.core.RequestAbstractType;
-import org.opensaml.saml2.core.Response;
-import org.opensaml.saml2.core.Status;
-import org.opensaml.saml2.core.StatusCode;
-import org.opensaml.ws.security.SecurityPolicyException;
-
-import edu.internet2.middleware.shibboleth.common.attribute.AttributeRequestException;
-import edu.internet2.middleware.shibboleth.common.attribute.SAML2AttributeAuthority;
-import edu.internet2.middleware.shibboleth.common.attribute.provider.ShibbolethAttributeRequestContext;
-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.RelyingPartyConfiguration;
-import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml2.AttributeQueryConfiguration;
-import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
-import edu.internet2.middleware.shibboleth.idp.session.Session;
-
-/**
- * SAML 2.0 Attribute Query profile handler.
- */
-public abstract class AbstractAttributeQuery extends AbstractSAML2ProfileHandler {
-
- /** Class logger. */
- private static Logger log = Logger.getLogger(AbstractAttributeQuery.class);
-
- /** {@inheritDoc} */
- public String getProfileId() {
- return "urn:oasis:names:tc:SAML:2.0:profiles:query";
- }
-
- /** {@inheritDoc} */
- public void processRequest(ProfileRequest<ServletRequest> request, ProfileResponse<ServletResponse> response)
- throws ProfileException {
-
- AttributeQueryContext queryContext = new AttributeQueryContext(request, response);
-
- getMessageDecoder(queryContext);
-
- try {
- decodeRequest(queryContext);
- buildAttributeRequestContext(queryContext);
- buildResponse(queryContext);
- } catch (SecurityPolicyException e) {
- buildErrorResponse(queryContext, e);
- } catch (AttributeRequestException e) {
- buildErrorResponse(queryContext, e);
- }
-
- getMessageEncoder(queryContext);
-
- try {
- queryContext.getMessageEncoder().encode();
- writeAuditLogEntry(queryContext);
- } catch (BindingException e) {
- log.error("Unable to encode response the relying party: "
- + queryContext.getAttributeRequestContext().getAttributeRequester(), e);
- throw new ProfileException("Unable to encode response the relying party: "
- + queryContext.getAttributeRequestContext().getAttributeRequester(), e);
- }
- }
-
- /**
- * Gets a populated message decoder.
- *
- * @param queryContext current request context
- *
- * @throws ProfileException thrown if there is no message decoder that may be used to decoder the incoming request
- */
- protected abstract void getMessageDecoder(AttributeQueryContext queryContext) throws ProfileException;
-
- /**
- * Gets a populated message encoder.
- *
- * @param queryContext current request context
- *
- * @throws ProfileException thrown if there is no message encoder that may be used to encoder the outgoing response
- */
- protected abstract void getMessageEncoder(AttributeQueryContext queryContext) throws ProfileException;
-
- /**
- * Decodes the message in the request and adds it to the request context.
- *
- * @param queryContext 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 queryContext) throws ProfileException, SecurityPolicyException {
-
- try {
- queryContext.getMessageDecoder().decode();
- if (log.isDebugEnabled()) {
- log.debug("decoded http servlet request");
- }
- } catch (BindingException e) {
- log.error("Error decoding attribute query message", e);
- throw new ProfileException("Error decoding attribute query message");
- }
- }
-
- /**
- * Creates an attribute request context for this attribute query and places it in the query context.
- *
- * @param queryContext current query context
- */
- protected void buildAttributeRequestContext(AttributeQueryContext queryContext) {
- AttributeQuery attributeQuery = (AttributeQuery) queryContext.getMessageDecoder().getSAMLMessage();
- RelyingPartyConfiguration rpConfig = getRelyingPartyConfiguration(attributeQuery.getIssuer().getValue());
-
- ShibbolethAttributeRequestContext requestContext = new ShibbolethAttributeRequestContext(getMetadataProvider(),
- rpConfig, attributeQuery);
- Session userSession = getSessionManager().getSession(getUserSessionId(queryContext.getProfileRequest()));
- if (userSession != null) {
- requestContext.setUserSession(userSession);
- ServiceInformation serviceInfo = userSession.getServiceInformation(attributeQuery.getIssuer().getValue());
- if (serviceInfo != null) {
- requestContext.setPrincipalAuthenticationMethod(serviceInfo.getAuthenticationMethod()
- .getAuthenticationMethod());
- }
- }
-
- requestContext.setEffectiveProfileConfiguration((AttributeQueryConfiguration) rpConfig
- .getProfileConfiguration(AttributeQueryConfiguration.PROFILE_ID));
-
- requestContext.setRequest(queryContext.getProfileRequest().getRawRequest());
- queryContext.setAttributeRequestContext(requestContext);
- }
-
- /**
- * Builds a response to the attribute query within the request context.
- *
- * @param queryContext current request context
- *
- * @throws ProfileException thrown if there is a problem creating the SAML response
- * @throws AttributeRequestException thrown if there is a problem resolving attributes
- */
- protected void buildResponse(AttributeQueryContext queryContext) throws ProfileException, AttributeRequestException {
- AttributeQueryConfiguration profileConfiguration = (AttributeQueryConfiguration) queryContext
- .getAttributeRequestContext().getEffectiveProfileConfiguration();
- DateTime issueInstant = new DateTime();
-
- // create the attribute statement
- AttributeStatement attributeStatement = buildAttributeStatement(queryContext);
-
- // create the assertion and add the attribute statement
- Assertion assertion = buildAssertion(issueInstant, queryContext.getAttributeRequestContext()
- .getRelyingPartyConfiguration(), profileConfiguration);
- assertion.getAttributeStatements().add(attributeStatement);
-
- // create the SAML response and add the assertion
- Response samlResponse = getResponseBuilder().buildObject();
- populateStatusResponse(samlResponse, issueInstant, (RequestAbstractType) queryContext
- .getAttributeRequestContext().getAttributeQuery(), queryContext.getAttributeRequestContext()
- .getRelyingPartyConfiguration());
-
- // TODO handle subject
- samlResponse.getAssertions().add(assertion);
-
- // sign the assertion if it should be signed
- signAssertion(assertion, queryContext.getAttributeRequestContext().getRelyingPartyConfiguration(),
- profileConfiguration);
-
- Status status = buildStatus(StatusCode.SUCCESS_URI, null, null);
- samlResponse.setStatus(status);
-
- queryContext.setAttributeQueryResponse(samlResponse);
- }
-
- /**
- * Executes a query for attributes and builds a SAML attribute statement from the results.
- *
- * @param queryContext 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 queryContext) throws ProfileException,
- AttributeRequestException {
-
- try {
- AttributeQueryConfiguration profileConfiguration = (AttributeQueryConfiguration) queryContext
- .getAttributeRequestContext().getEffectiveProfileConfiguration();
- if (profileConfiguration == null) {
- log.error("No SAML 2 attribute query profile configuration is defined for relying party: "
- + queryContext.getAttributeRequestContext().getRelyingPartyConfiguration().getRelyingPartyId());
- throw new AttributeRequestException(
- "SAML 2 attribute query is not configured for this relying party");
- }
-
- SAML2AttributeAuthority attributeAuthority = profileConfiguration.getAttributeAuthority();
- return attributeAuthority.performAttributeQuery(queryContext.getAttributeRequestContext());
- } catch (AttributeRequestException e) {
- log.error("Error resolving attributes", e);
- throw e;
- }
- }
-
- /**
- * Constructs an SAML response message carrying a request error.
- *
- * @param queryContext current request context
- * @param error the encountered error
- */
- protected void buildErrorResponse(AttributeQueryContext queryContext, Exception error) {
- AttributeQuery attributeQuery = (AttributeQuery) queryContext.getAttributeRequestContext().getAttributeQuery();
- RelyingPartyConfiguration rpConfig = queryContext.getAttributeRequestContext().getRelyingPartyConfiguration();
-
- DateTime issueInstant = new DateTime();
- Response samlResponse = getResponseBuilder().buildObject();
- populateStatusResponse(samlResponse, issueInstant, attributeQuery, rpConfig);
-
- Status status = buildStatus(StatusCode.REQUESTER_URI, StatusCode.REQUEST_DENIED_URI, error
- .getLocalizedMessage());
-
- samlResponse.setStatus(status);
-
- queryContext.setAttributeQueryResponse(samlResponse);
- }
-
- /**
- * Writes an aduit log entry indicating the successful response to the attribute request.
- *
- * @param queryContext current request context
- */
- protected void writeAuditLogEntry(AttributeQueryContext queryContext) {
- AuditLogEntry auditLogEntry = new AuditLogEntry();
- auditLogEntry.setMessageProfile(getProfileId());
- auditLogEntry.setPrincipalAuthenticationMethod(queryContext.getAttributeRequestContext()
- .getPrincipalAuthenticationMethod());
- auditLogEntry.setPrincipalId(queryContext.getAttributeRequestContext().getPrincipalName());
- auditLogEntry.setProviderId(queryContext.getAttributeRequestContext().getRelyingPartyConfiguration()
- .getProviderId());
- auditLogEntry.setRelyingPartyId(queryContext.getAttributeRequestContext().getAttributeRequester());
- auditLogEntry.setRequestBinding(queryContext.getMessageDecoder().getBindingURI());
- auditLogEntry.setRequestId(((AttributeQuery) queryContext.getAttributeRequestContext().getAttributeQuery())
- .getID());
- auditLogEntry.setResponseBinding(queryContext.getMessageEncoder().getBindingURI());
- auditLogEntry.setResponseId(queryContext.getAttributeQueryResponse().getID());
- getAduitLog().log(Level.CRITICAL, auditLogEntry);
- }
-
- /** Basic data structure used to accumulate information as a request is being processed. */
- protected class AttributeQueryContext {
-
- /** Curent profile request. */
- private ProfileRequest<ServletRequest> profileRequest;
-
- /** Current profile response. */
- private ProfileResponse<ServletResponse> profileResponse;
-
- /** Decoder used to decode the incoming request. */
- private MessageDecoder<ServletRequest> messageDecoder;
-
- /** Attribute request context for this attribute query. */
- private ShibbolethAttributeRequestContext attributeRequestContext;
-
- /** Encoder used to encode the outgoing response. */
- private MessageEncoder<ServletResponse> messageEncoder;
-
- /** Attribute query response to the relying party. */
- private Response attributeQueryResponse;
-
- /**
- * Constructor.
- *
- * @param request current profile request
- * @param response current profile response
- */
- public AttributeQueryContext(ProfileRequest<ServletRequest> request, ProfileResponse<ServletResponse> response) {
- profileRequest = request;
- profileResponse = response;
- }
-
- /**
- * Gets the attribute request context for this query.
- *
- * @return attribute request context for this query
- */
- public ShibbolethAttributeRequestContext getAttributeRequestContext() {
- return attributeRequestContext;
- }
-
- /**
- * Sets the attribute request context for this query.
- *
- * @param context attribute request context for this query
- */
- public void setAttributeRequestContext(ShibbolethAttributeRequestContext context) {
- attributeRequestContext = context;
- }
-
- /**
- * Gets the attribute query response.
- *
- * @return attribute query response
- */
- public Response getAttributeQueryResponse() {
- return attributeQueryResponse;
- }
-
- /**
- * Sets the attribute query response.
- *
- * @param response attribute query response
- */
- public void setAttributeQueryResponse(Response response) {
- attributeQueryResponse = response;
- }
-
- /**
- * Gets the decoder used to decode the request.
- *
- * @return decoder used to decode the request
- */
- public MessageDecoder<ServletRequest> getMessageDecoder() {
- return messageDecoder;
- }
-
- /**
- * Sets the decoder used to decode the request.
- *
- * @param decoder decoder used to decode the request
- */
- public void setMessageDecoder(MessageDecoder<ServletRequest> decoder) {
- messageDecoder = decoder;
- }
-
- /**
- * Gets the encoder used to encoder the response.
- *
- * @return encoder used to encoder the response
- */
- public MessageEncoder<ServletResponse> getMessageEncoder() {
- return messageEncoder;
- }
-
- /**
- * Sets the encoder used to encoder the response.
- *
- * @param encoder encoder used to encoder the response
- */
- public void setMessageEncoder(MessageEncoder<ServletResponse> encoder) {
- messageEncoder = encoder;
- }
-
- /**
- * Gets the current profile request.
- *
- * @return current profile request
- */
- public ProfileRequest<ServletRequest> getProfileRequest() {
- return profileRequest;
- }
-
- /**
- * Gets the current profile response.
- *
- * @return current profile response
- */
- public ProfileResponse<ServletResponse> getProfileResponse() {
- return profileResponse;
- }
- }
-}
\ No newline at end of file
package edu.internet2.middleware.shibboleth.idp.profile.saml2;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
-import org.joda.time.DateTime;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import org.joda.time.DateTime;
import org.opensaml.common.SAMLObjectBuilder;
import org.opensaml.common.SAMLVersion;
import org.opensaml.common.impl.SAMLObjectContentReference;
-
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.log.Level;
import org.opensaml.saml2.core.Advice;
import org.opensaml.saml2.core.Assertion;
import org.opensaml.saml2.core.Audience;
import org.opensaml.saml2.core.AudienceRestriction;
+import org.opensaml.saml2.core.AuthnRequest;
import org.opensaml.saml2.core.Conditions;
import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.NameID;
import org.opensaml.saml2.core.ProxyRestriction;
import org.opensaml.saml2.core.RequestAbstractType;
import org.opensaml.saml2.core.Response;
+import org.opensaml.saml2.core.Statement;
import org.opensaml.saml2.core.Status;
import org.opensaml.saml2.core.StatusCode;
import org.opensaml.saml2.core.StatusMessage;
import org.opensaml.saml2.core.StatusResponseType;
import org.opensaml.saml2.core.Subject;
-
+import org.opensaml.saml2.core.SubjectConfirmation;
+import org.opensaml.saml2.metadata.AttributeAuthorityDescriptor;
+import org.opensaml.saml2.metadata.AuthnAuthorityDescriptor;
+import org.opensaml.saml2.metadata.NameIDFormat;
+import org.opensaml.saml2.metadata.PDPDescriptor;
+import org.opensaml.saml2.metadata.RoleDescriptor;
+import org.opensaml.saml2.metadata.SSODescriptor;
+import org.opensaml.saml2.metadata.provider.MetadataProviderException;
import org.opensaml.xml.XMLObjectBuilder;
-import org.opensaml.xml.encryption.EncryptionException;
import org.opensaml.xml.security.credential.Credential;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.Signer;
import org.opensaml.xml.util.DatatypeHelper;
-import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
+import edu.internet2.middleware.shibboleth.common.attribute.AttributeRequestException;
+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;
/** For building subject. */
private SAMLObjectBuilder<Subject> subjectBuilder;
+ /** For builder subject confirmation. */
+ private SAMLObjectBuilder<SubjectConfirmation> subjectConfirmationBuilder;
+
/** For building conditions. */
private SAMLObjectBuilder<Conditions> conditionsBuilder;
/** Constructor. */
@SuppressWarnings("unchecked")
protected AbstractSAML2ProfileHandler() {
-
super();
responseBuilder = (SAMLObjectBuilder<Response>) getBuilderFactory().getBuilder(Response.DEFAULT_ELEMENT_NAME);
assertionBuilder = (SAMLObjectBuilder<Assertion>) getBuilderFactory()
.getBuilder(Assertion.DEFAULT_ELEMENT_NAME);
subjectBuilder = (SAMLObjectBuilder<Subject>) getBuilderFactory().getBuilder(Subject.DEFAULT_ELEMENT_NAME);
+ subjectConfirmationBuilder = (SAMLObjectBuilder<SubjectConfirmation>) getBuilderFactory().getBuilder(
+ SubjectConfirmation.DEFAULT_ELEMENT_NAME);
conditionsBuilder = (SAMLObjectBuilder<Conditions>) getBuilderFactory().getBuilder(
Conditions.DEFAULT_ELEMENT_NAME);
audienceRestrictionBuilder = (SAMLObjectBuilder<AudienceRestriction>) getBuilderFactory().getBuilder(
}
/**
- * Populates the response's id, in response to, issue instant, version, and issuer properties.
+ * Convenience method for getting the SAML 2 subject confirmation builder.
*
- * @param response the response to populate
- * @param issueInstant timestamp to use as the issue instant for the response
- * @param request the request that the response is for
- * @param rpConfig the relying party configuration for the request
+ * @return SAML 2 subject confirmation builder
*/
- protected void populateStatusResponse(StatusResponseType response, DateTime issueInstant,
- RequestAbstractType request, RelyingPartyConfiguration rpConfig) {
-
- response.setID(getIdGenerator().generateIdentifier());
- response.setInResponseTo(request.getID());
- response.setIssueInstant(issueInstant);
- response.setVersion(SAMLVersion.VERSION_20);
- response.setIssuer(buildEntityIssuer(rpConfig));
+ public SAMLObjectBuilder<SubjectConfirmation> getSubjectConfirmationBuilder() {
+ return subjectConfirmationBuilder;
}
/**
- * Build a status message, with an optional second-level failure message.
+ * Builds a response to the attribute query within the 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.
+ * @param requestContext current request context
+ * @param assertionSubject subject of the assertion within the response
+ * @param statements the statements to include in the response
*
- * @return a Status object.
+ * @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 Status buildStatus(String topLevelCode, String secondLevelCode, String secondLevelFailureMessage) {
+ protected Response buildResponse(SAML2ProfileRequestContext requestContext, Subject assertionSubject,
+ List<Statement> statements) throws ProfileException, AttributeRequestException {
- Status status = statusBuilder.buildObject();
-
- StatusCode statusCode = statusCodeBuilder.buildObject();
- statusCode.setValue(DatatypeHelper.safeTrimOrNullString(topLevelCode));
- status.setStatusCode(statusCode);
-
- if (secondLevelCode != null) {
- StatusCode secondLevelStatusCode = statusCodeBuilder.buildObject();
- secondLevelStatusCode.setValue(DatatypeHelper.safeTrimOrNullString(secondLevelCode));
- statusCode.setStatusCode(secondLevelStatusCode);
- }
+ DateTime issueInstant = new DateTime();
- if (secondLevelFailureMessage != null) {
- StatusMessage msg = statusMessageBuilder.buildObject();
- msg.setMessage(secondLevelFailureMessage);
- status.setStatusMessage(msg);
+ // create the assertion and add the attribute statement
+ Assertion assertion = buildAssertion(requestContext, issueInstant);
+ assertion.setSubject(assertionSubject);
+ if (statements != null) {
+ assertion.getStatements().addAll(statements);
}
- return status;
+ // create the SAML response and add the assertion
+ Response samlResponse = getResponseBuilder().buildObject();
+ populateStatusResponse(requestContext, samlResponse);
+
+ samlResponse.getAssertions().add(assertion);
+
+ // sign the assertion if it should be signed
+ signAssertion(requestContext, assertion);
+
+ Status status = buildStatus(StatusCode.SUCCESS_URI, null, null);
+ samlResponse.setStatus(status);
+
+ return samlResponse;
}
/**
* Builds a basic assertion with its id, issue instant, SAML version, issuer, subject, and conditions populated.
*
+ * @param requestContext current request context
* @param issueInstant time to use as assertion issue instant
- * @param rpConfig the relying party configuration
- * @param profileConfig current profile configuration
*
* @return the built assertion
*/
- protected Assertion buildAssertion(final DateTime issueInstant, final RelyingPartyConfiguration rpConfig,
- final AbstractSAML2ProfileConfiguration profileConfig) {
+ protected Assertion buildAssertion(SAML2ProfileRequestContext requestContext, DateTime issueInstant) {
- Assertion assertion = assertionBuilder.buildObject();
+ Assertion assertion = getAssertionBuilder().buildObject();
assertion.setID(getIdGenerator().generateIdentifier());
assertion.setIssueInstant(issueInstant);
assertion.setVersion(SAMLVersion.VERSION_20);
- assertion.setIssuer(buildEntityIssuer(rpConfig));
- // TODO assertion.setSubject(buildSubject());
+ assertion.setIssuer(buildEntityIssuer(requestContext));
- Conditions conditions = buildConditions(issueInstant, profileConfig);
+ Conditions conditions = buildConditions(requestContext, issueInstant);
assertion.setConditions(conditions);
return assertion;
}
/**
- * Builds an entity type Issuer populated with the correct provider Id for this relying party configuration.
+ * Creates an {@link Issuer} populated with information about the relying party.
*
- * @param rpConfig the relying party configuration
+ * @param requestContext current request context
*
- * @return the built Issuer
+ * @return the built issuer
*/
- protected Issuer buildEntityIssuer(final RelyingPartyConfiguration rpConfig) {
-
+ protected Issuer buildEntityIssuer(SAML2ProfileRequestContext requestContext) {
Issuer issuer = getIssuerBuilder().buildObject();
issuer.setFormat(Issuer.ENTITY);
- issuer.setValue(rpConfig.getProviderId());
+ issuer.setValue(requestContext.getRelyingPartyId());
return issuer;
}
/**
- * Builds the SAML subject for the user for the service provider.
- *
- * @return SAML subject for the user for the service provider
- *
- * @throws EncryptionException thrown if there is a problem encryption the subject's NameID
- */
- protected Subject buildSubject() throws EncryptionException {
- // TODO
- return null;
- }
-
- /**
* Builds a SAML assertion condition set. The following fields are set; not before, not on or after, audience
* restrictions, and proxy restrictions.
*
+ * @param requestContext current request context
* @param issueInstant timestamp the assertion was created
- * @param profileConfig current profile configuration
*
* @return constructed conditions
*/
- protected Conditions buildConditions(final DateTime issueInstant,
- final AbstractSAML2ProfileConfiguration profileConfig) {
+ protected Conditions buildConditions(SAML2ProfileRequestContext requestContext, DateTime issueInstant) {
+ AbstractSAML2ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
- Conditions conditions = conditionsBuilder.buildObject();
+ Conditions conditions = getConditionsBuilder().buildObject();
conditions.setNotBefore(issueInstant);
conditions.setNotOnOrAfter(issueInstant.plus(profileConfig.getAssertionLifetime()));
// add audience restrictions
audiences = profileConfig.getAssertionAudiences();
if (audiences != null && audiences.size() > 0) {
- AudienceRestriction audienceRestriction = audienceRestrictionBuilder.buildObject();
+ AudienceRestriction audienceRestriction = getAudienceRestrictionBuilder().buildObject();
for (String audienceUri : audiences) {
- Audience audience = audienceBuilder.buildObject();
+ Audience audience = getAudienceBuilder().buildObject();
audience.setAudienceURI(audienceUri);
audienceRestriction.getAudiences().add(audience);
}
// add proxy restrictions
audiences = profileConfig.getProxyAudiences();
if (audiences != null && audiences.size() > 0) {
- ProxyRestriction proxyRestriction = proxyRestrictionBuilder.buildObject();
+ ProxyRestriction proxyRestriction = getProxyRestrictionBuilder().buildObject();
Audience audience;
for (String audienceUri : audiences) {
- audience = audienceBuilder.buildObject();
+ audience = getAudienceBuilder().buildObject();
audience.setAudienceURI(audienceUri);
proxyRestriction.getAudiences().add(audience);
}
}
/**
+ * Populates the response's id, in response to, issue instant, version, and issuer properties.
+ *
+ * @param requestContext current request context
+ * @param response the response to populate
+ */
+ protected void populateStatusResponse(SAML2ProfileRequestContext requestContext, StatusResponseType response) {
+ response.setID(getIdGenerator().generateIdentifier());
+ response.setInResponseTo(requestContext.getSamlRequest().getID());
+ response.setIssueInstant(response.getIssueInstant());
+ response.setVersion(SAMLVersion.VERSION_20);
+ response.setIssuer(buildEntityIssuer(requestContext));
+ }
+
+ /**
* Signs the given assertion if either the current profile configuration or the relying party configuration contains
* signing credentials.
*
+ * @param requestContext current request context
* @param assertion assertion to sign
- * @param rpConfig relying party configuration
- * @param profileConfig current profile configuration
*/
- protected void signAssertion(Assertion assertion, RelyingPartyConfiguration rpConfig,
- AbstractSAML2ProfileConfiguration profileConfig) {
+ protected void signAssertion(SAML2ProfileRequestContext requestContext, Assertion assertion) {
+ AbstractSAML2ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
+
if (!profileConfig.getSignAssertions()) {
return;
}
Credential signatureCredential = profileConfig.getSigningCredential();
if (signatureCredential == null) {
- signatureCredential = rpConfig.getDefaultSigningCredential();
+ signatureCredential = requestContext.getRelyingPartyConfiguration().getDefaultSigningCredential();
}
if (signatureCredential == null) {
Signer.signObject(signature);
}
- // TODO encryption support
+ /**
+ * Build a status message, with an optional second-level failure message.
+ *
+ * @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 a Status object.
+ */
+ protected Status buildStatus(String topLevelCode, String secondLevelCode, String secondLevelFailureMessage) {
+
+ Status status = getStatusBuilder().buildObject();
+
+ StatusCode statusCode = getStatusCodeBuilder().buildObject();
+ statusCode.setValue(DatatypeHelper.safeTrimOrNullString(topLevelCode));
+ status.setStatusCode(statusCode);
+
+ if (secondLevelCode != null) {
+ StatusCode secondLevelStatusCode = getStatusCodeBuilder().buildObject();
+ secondLevelStatusCode.setValue(DatatypeHelper.safeTrimOrNullString(secondLevelCode));
+ statusCode.setStatusCode(secondLevelStatusCode);
+ }
+
+ if (secondLevelFailureMessage != null) {
+ StatusMessage msg = getStatusMessageBuilder().buildObject();
+ msg.setMessage(secondLevelFailureMessage);
+ status.setStatusMessage(msg);
+ }
+
+ return status;
+ }
+
+ /**
+ * Builds the SAML subject for the user for the service provider.
+ *
+ * @param requestContext current request context
+ * @param confirmationMethod subject confirmation method used for the subject
+ *
+ * @return SAML subject for the user for the service provider
+ */
+ protected Subject buildSubject(SAML2ProfileRequestContext requestContext, String confirmationMethod) {
+ NameID nameID = requestContext.getSubjectNameID();
+ // TODO handle encryption
+
+ SubjectConfirmation subjectConfirmation = getSubjectConfirmationBuilder().buildObject();
+ subjectConfirmation.setMethod(confirmationMethod);
+
+ Subject subject = getSubjectBuilder().buildObject();
+ subject.setNameID(nameID);
+ subject.getSubjectConfirmations().add(subjectConfirmation);
+
+ return subject;
+ }
+
+ /**
+ * 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) {
+ Response samlResponse = getResponseBuilder().buildObject();
+ samlResponse.setIssueInstant(new DateTime());
+ populateStatusResponse(requestContext, samlResponse);
+
+ Status status = buildStatus(topLevelCode, secondLevelCode, secondLevelFailureMessage);
+ samlResponse.setStatus(status);
+
+ return samlResponse;
+ }
+
+ /**
+ * Gets the NameID format to use when creating NameIDs for the relying party.
+ *
+ * @param requestContext current request context
+ *
+ * @return list of nameID formats that may be used with the relying party
+ *
+ * @throws ProfileException thrown if there is a problem determing the NameID format to use
+ */
+ protected List<String> getNameIDFormat(SAML2ProfileRequestContext requestContext) throws ProfileException {
+ ArrayList<String> nameFormats = new ArrayList<String>();
+
+ try {
+ RoleDescriptor assertingPartyRole = getMetadataProvider().getRole(requestContext.getAssertingPartyId(),
+ requestContext.getAssertingPartyRole(), SAMLConstants.SAML20P_NS);
+ List<String> assertingPartySupportedFormats = getEntitySupportedFormats(assertingPartyRole);
+
+ String nameFormat = null;
+ if (requestContext.getSamlRequest() instanceof AuthnRequest) {
+ AuthnRequest authnRequest = (AuthnRequest) requestContext.getSamlRequest();
+ if (authnRequest.getNameIDPolicy() != null) {
+ nameFormat = authnRequest.getNameIDPolicy().getFormat();
+ if (assertingPartySupportedFormats.contains(nameFormat)) {
+ nameFormats.add(nameFormat);
+ } else {
+ throw new ProfileException("NameID format required by relying party is not supported");
+ }
+ }
+ }
+
+ if (nameFormats.isEmpty()) {
+ RoleDescriptor relyingPartyRole = getMetadataProvider().getRole(requestContext.getRelyingPartyId(),
+ requestContext.getRelyingPartyRole(), SAMLConstants.SAML20P_NS);
+ List<String> relyingPartySupportedFormats = getEntitySupportedFormats(relyingPartyRole);
+
+ assertingPartySupportedFormats.retainAll(relyingPartySupportedFormats);
+ nameFormats.addAll(assertingPartySupportedFormats);
+ }
+ if (nameFormats.isEmpty()) {
+ nameFormats.add("urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified");
+ }
+
+ return nameFormats;
+
+ } catch (MetadataProviderException e) {
+ throw new ProfileException("Unable to determine lookup entity metadata", e);
+ }
+ }
+
+ /**
+ * Gets the list of NameID formats supported for a given role.
+ *
+ * @param role the role to get the list of supported NameID formats
+ *
+ * @return list of supported NameID formats
+ */
+ protected List<String> getEntitySupportedFormats(RoleDescriptor role) {
+ List<NameIDFormat> nameIDFormats = null;
+
+ if (role instanceof SSODescriptor) {
+ nameIDFormats = ((SSODescriptor) role).getNameIDFormats();
+ } else if (role instanceof AuthnAuthorityDescriptor) {
+ nameIDFormats = ((AuthnAuthorityDescriptor) role).getNameIDFormats();
+ } else if (role instanceof PDPDescriptor) {
+ nameIDFormats = ((PDPDescriptor) role).getNameIDFormats();
+ } else if (role instanceof AttributeAuthorityDescriptor) {
+ nameIDFormats = ((AttributeAuthorityDescriptor) role).getNameIDFormats();
+ }
+
+ ArrayList<String> supportedFormats = new ArrayList<String>();
+ if (nameIDFormats != null) {
+ for (NameIDFormat format : nameIDFormats) {
+ supportedFormats.add(format.getFormat());
+ }
+ }
+
+ return supportedFormats;
+ }
+
+ /**
+ * Writes an aduit log entry indicating the successful response to the attribute request.
+ *
+ * @param context current request context
+ */
+ protected void writeAuditLogEntry(SAML2ProfileRequestContext context) {
+ AuditLogEntry auditLogEntry = new AuditLogEntry();
+ auditLogEntry.setMessageProfile(getProfileId());
+ auditLogEntry.setPrincipalAuthenticationMethod(context.getPrincipalAuthenticationMethod());
+ auditLogEntry.setPrincipalName(context.getPrincipalName());
+ auditLogEntry.setAssertingPartyId(context.getAssertingPartyId());
+ auditLogEntry.setRelyingPartyId(context.getRelyingPartyId());
+ auditLogEntry.setRequestBinding(context.getMessageDecoder().getBindingURI());
+ auditLogEntry.setRequestId(context.getSamlRequest().getID());
+ auditLogEntry.setResponseBinding(context.getMessageEncoder().getBindingURI());
+ auditLogEntry.setResponseId(context.getSamlResponse().getID());
+ getAduitLog().log(Level.CRITICAL, auditLogEntry);
+ }
+
+ /**
+ * Contextual object used to accumlate information as profile requests are being processed.
+ *
+ * @param <RequestType> type of SAML 2 request
+ * @param <ResponseType> type of SAML 2 response
+ * @param <ProfileConfigurationType> configuration type for this profile
+ */
+ protected class SAML2ProfileRequestContext<RequestType extends RequestAbstractType,
+ ResponseType extends StatusResponseType,
+ ProfileConfigurationType extends AbstractSAML2ProfileConfiguration>
+ extends SAMLProfileRequestContext {
+
+ /** SAML request message. */
+ private RequestType samlRequest;
+
+ /** SAML response message. */
+ private ResponseType samlResponse;
+
+ /** Request profile configuration. */
+ private ProfileConfigurationType profileConfiguration;
+
+ /** The NameID of the subject of this request. */
+ private NameID subjectNameID;
+
+ /**
+ * Constructor.
+ *
+ * @param request current profile request
+ * @param response current profile response
+ */
+ public SAML2ProfileRequestContext(ProfileRequest<ServletRequest> request,
+ ProfileResponse<ServletResponse> response) {
+ super(request, response);
+ }
+
+ /**
+ * Gets the NameID of the subject of this request.
+ *
+ * @return NameID of the subject of this request
+ */
+ public NameID getSubjectNameID() {
+ return subjectNameID;
+ }
+
+ /**
+ * Sets the NameID of the subject of this request.
+ *
+ * @param nameID NameID of the subject of this request
+ */
+ public void setSubjectNameID(NameID nameID) {
+ subjectNameID = nameID;
+ }
+
+ /**
+ * Gets the profile configuration for this request.
+ *
+ * @return profile configuration for this request
+ */
+ public ProfileConfigurationType getProfileConfiguration() {
+ return profileConfiguration;
+ }
+
+ /**
+ * Sets the profile configuration for this request.
+ *
+ * @param configuration profile configuration for this request
+ */
+ public void setProfileConfiguration(ProfileConfigurationType configuration) {
+ profileConfiguration = configuration;
+ }
+
+ /**
+ * Gets the SAML request message.
+ *
+ * @return SAML request message
+ */
+ public RequestType getSamlRequest() {
+ return samlRequest;
+ }
+
+ /**
+ * Sets the SAML request message.
+ *
+ * @param request SAML request message
+ */
+ public void setSamlRequest(RequestType request) {
+ samlRequest = request;
+ }
+
+ /**
+ * Gets the SAML response message.
+ *
+ * @return SAML response message
+ */
+ public ResponseType getSamlResponse() {
+ return samlResponse;
+ }
+
+ /**
+ * Sets the SAML response message.
+ *
+ * @param response SAML response message
+ */
+ public void setSamlResponse(ResponseType response) {
+ samlResponse = response;
+ }
+ }
}
\ No newline at end of file
--- /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.util.ArrayList;
+import java.util.Map;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.log4j.Logger;
+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.AttributeQuery;
+import org.opensaml.saml2.core.AttributeStatement;
+import org.opensaml.saml2.core.NameID;
+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.AttributeAuthorityDescriptor;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.ws.security.SecurityPolicyException;
+
+import edu.internet2.middleware.shibboleth.common.attribute.AttributeRequestException;
+import edu.internet2.middleware.shibboleth.common.attribute.BaseAttribute;
+import edu.internet2.middleware.shibboleth.common.attribute.provider.SAML2AttributeAuthority;
+import edu.internet2.middleware.shibboleth.common.attribute.provider.ShibbolethSAMLAttributeRequestContext;
+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.AttributeQueryConfiguration;
+import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
+import edu.internet2.middleware.shibboleth.idp.session.Session;
+
+/**
+ * SAML 2.0 Attribute Query profile handler.
+ */
+public class AttributeQueryProfileHandler extends AbstractSAML2ProfileHandler {
+
+ /** Class logger. */
+ private static Logger log = Logger.getLogger(AttributeQueryProfileHandler.class);
+
+ /** SAML binding URI. */
+ private static final String BINDING = "urn:oasis:names:tc:SAML:2.0:bindings:SOAP";
+
+ /** {@inheritDoc} */
+ public String getProfileId() {
+ return "urn:mace:shibboleth:2.0:idp:profiles:saml2:query:attribute";
+ }
+
+ /** {@inheritDoc} */
+ public void processRequest(ProfileRequest<ServletRequest> request, ProfileResponse<ServletResponse> response)
+ throws ProfileException {
+
+ AttributeQueryContext requestContext = new AttributeQueryContext(request, response);
+
+ Response samlResponse;
+ try {
+ decodeRequest(requestContext);
+
+ // populate request context with information from decoded message
+ SAMLSecurityPolicy securityPolicy = requestContext.getMessageDecoder().getSecurityPolicy();
+ requestContext.setRelyingPartyId(securityPolicy.getIssuer());
+ requestContext
+ .setRelyingPartyConfiguration(getRelyingPartyConfiguration(requestContext.getRelyingPartyId()));
+ requestContext.setRelyingPartyRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+ requestContext.setAssertingPartyId(requestContext.getRelyingPartyConfiguration().getProviderId());
+ requestContext.setAssertingPartyRole(AttributeAuthorityDescriptor.DEFAULT_ELEMENT_NAME);
+ requestContext.setProfileConfiguration((AttributeQueryConfiguration) getProfileConfiguration(requestContext
+ .getRelyingPartyId(), AttributeQueryConfiguration.PROFILE_ID));
+ requestContext.setSamlRequest((AttributeQuery) requestContext.getMessageDecoder().getSAMLMessage());
+
+ // TODO principal
+
+ // create the SAML attribute statement
+ ArrayList<Statement> statements = new ArrayList<Statement>();
+ statements.add(buildAttributeStatement(requestContext));
+
+ //TODO NameID
+ Subject assertionSubject = buildSubject(requestContext, "urn:oasis:names:tc:SAML:2.0:cm:sender-vouches");
+
+ // 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());
+ }
+
+ requestContext.setSamlResponse(samlResponse);
+
+ encodeResponse(requestContext);
+ writeAuditLogEntry(requestContext);
+ }
+
+ /**
+ * Decodes the message in the request and adds it to the request context.
+ *
+ * @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 {
+ MessageDecoder<ServletRequest> decoder = getMessageDecoderFactory().getMessageDecoder(BINDING);
+ if (decoder == null) {
+ throw new ProfileException("No request decoder was registered for binding type: " + BINDING);
+ }
+
+ super.populateMessageDecoder(decoder);
+ decoder.setRequest(requestContext.getProfileRequest().getRawRequest());
+ requestContext.setMessageDecoder(decoder);
+
+ try {
+ decoder.decode();
+ if (log.isDebugEnabled()) {
+ log.debug("decoded http servlet request");
+ }
+ } catch (BindingException e) {
+ log.error("Error decoding attribute query message", e);
+ throw new ProfileException("Error decoding attribute query message");
+ }
+ }
+
+ /**
+ * 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 {
+
+ 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();
+
+ 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", 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());
+
+ 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);
+ }
+ }
+
+ queryContext.setProfileConfiguration(requestContext.getProfileConfiguration());
+ queryContext.setRequest(requestContext.getProfileRequest());
+
+ return queryContext;
+ }
+
+ /**
+ * 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(AttributeQueryContext requestContext) throws ProfileException {
+ MessageEncoder<ServletResponse> encoder = getMessageEncoderFactory().getMessageEncoder(BINDING);
+ if (encoder == null) {
+ throw new ProfileException("No response encoder was registered for binding type: " + BINDING);
+ }
+
+ super.populateMessageEncoder(encoder);
+ encoder.setResponse(requestContext.getProfileResponse().getRawResponse());
+ encoder.setSamlMessage(requestContext.getSamlResponse());
+ requestContext.setMessageEncoder(encoder);
+ }
+
+ /** Basic data structure used to accumulate information as a request is being processed. */
+ protected class AttributeQueryContext extends
+ SAML2ProfileRequestContext<AttributeQuery, Response, AttributeQueryConfiguration> {
+
+ /**
+ * Constructor.
+ *
+ * @param request current profile request
+ * @param response current profile response
+ */
+ public AttributeQueryContext(ProfileRequest<ServletRequest> request, ProfileResponse<ServletResponse> response) {
+ super(request, response);
+ }
+ }
+}
\ No newline at end of file
+++ /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 org.opensaml.common.binding.decoding.MessageDecoder;
-import org.opensaml.common.binding.encoding.MessageEncoder;
-
-import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
-
-/**
- * SAML 2.0 SOAP Attribute Query profile handler.
- */
-public class HTTPSOAPAttributeQuery extends AbstractAttributeQuery {
-
- /** SAML binding URI. */
- public static final String BINDING = "urn:oasis:names:tc:SAML:2.0:bindings:SOAP";
-
- /** Constructor. */
- public HTTPSOAPAttributeQuery() {
- super();
- }
-
- /** {@inheritDoc} */
- @SuppressWarnings("unchecked")
- protected void getMessageDecoder(AttributeQueryContext requestContext) throws ProfileException {
- MessageDecoder<ServletRequest> decoder = getMessageDecoderFactory().getMessageDecoder(BINDING);
- if (decoder == null) {
- throw new ProfileException("No request decoder was registered for binding type: " + BINDING);
- }
-
- super.populateMessageDecoder(decoder);
- decoder.setRequest(requestContext.getProfileRequest().getRawRequest());
- requestContext.setMessageDecoder(decoder);
- }
-
- /** {@inheritDoc} */
- @SuppressWarnings("unchecked")
- protected void getMessageEncoder(AttributeQueryContext requestContext) throws ProfileException {
-
- MessageEncoder<ServletResponse> encoder = getMessageEncoderFactory().getMessageEncoder(BINDING);
- if (encoder == null) {
- throw new ProfileException("No response encoder was registered for binding type: " + BINDING);
- }
-
- super.populateMessageEncoder(encoder);
- encoder.setResponse(requestContext.getProfileResponse().getRawResponse());
- encoder.setSamlMessage(requestContext.getAttributeQueryResponse());
- requestContext.setMessageEncoder(encoder);
- }
-}
\ No newline at end of file
<resolver:AttributeDefinition xsi:type="simple:Simple" id="cn">
<resolver:DataConnectorDependency ref="static" />
</resolver:AttributeDefinition>
+
+ <resolver:AttributeDefinition xsi:type="simple:Simple" id="email">
+ <resolver:DataConnectorDependency ref="static" />
+ </resolver:AttributeDefinition>
<resolver:DataConnector xsi:type="static:Static" id="static">
<static:Attribute id="uid">
<static:Attribute id="cn">
<static:Value>Test User</static:Value>
</static:Attribute>
+ <static:Attribute id="email">
+ <static:Value>t.user@example.org</static:Value>
+ </static:Attribute>
</resolver:DataConnector>
<resolver:PrincipalConnector xsi:type="pc:Direct"