--- /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.saml1;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.log4j.Logger;
+import org.opensaml.Configuration;
+import org.opensaml.common.SAMLObject;
+import org.opensaml.common.SAMLVersion;
+import org.opensaml.common.binding.BindingException;
+import org.opensaml.common.binding.MessageDecoder;
+import org.opensaml.common.binding.MessageEncoder;
+import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
+import org.opensaml.xml.XMLObjectBuilderFactory;
+
+import edu.internet2.middleware.shibboleth.common.attribute.filtering.FilteringEngine;
+import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolver;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
+import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
+
+/**
+ * Common implementation details for profile handlers.
+ */
+public abstract class AbstractProfileHandler implements ProfileHandler {
+
+ /** SAML Version for this profile handler. */
+ public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_11;
+
+ /** Class logger. */
+ private static Logger log = Logger.getLogger(AbstractProfileHandler.class);
+
+ /** For building XML. */
+ private XMLObjectBuilderFactory builderFactory;
+
+ /** For generating random ids. */
+ private SecureRandomIdentifierGenerator idGenerator;
+
+ /** For decoding requests. */
+ private MessageDecoder<ServletRequest> decoder;
+
+ /** For encoding responses. */
+ private MessageEncoder<ServletResponse> encoder;
+
+ /** Relying party configuration. */
+ private RelyingPartyConfiguration relyingPartyConfiguration;
+
+ /** For resolving attributes. */
+ private AttributeResolver resolver;
+
+ /** To determine releasable attributes. */
+ private FilteringEngine engine;
+
+ /**
+ * Default constructor.
+ */
+ public AbstractProfileHandler() {
+ builderFactory = Configuration.getBuilderFactory();
+ idGenerator = new SecureRandomIdentifierGenerator();
+ }
+
+ /**
+ * Returns the XML builder factory.
+ *
+ * @return Returns the builderFactory.
+ */
+ public XMLObjectBuilderFactory getBuilderFactory() {
+ return builderFactory;
+ }
+
+ /**
+ * Returns the id generator.
+ *
+ * @return Returns the idGenerator.
+ */
+ public SecureRandomIdentifierGenerator getIdGenerator() {
+ return idGenerator;
+ }
+
+ /**
+ * Sets the decoder.
+ *
+ * @param d <code>MessageDecoder</code>
+ */
+ public void setDecoder(MessageDecoder<ServletRequest> d) {
+ decoder = d;
+ }
+
+ /**
+ * Returns the decoder.
+ *
+ * @return <code>MessageDecoder</code>
+ */
+ public MessageDecoder<ServletRequest> getDecoder() {
+ return decoder;
+ }
+
+ /**
+ * Sets the encoder.
+ *
+ * @param e <code>MessageEncoder</code>
+ */
+ public void setEncoder(MessageEncoder<ServletResponse> e) {
+ encoder = e;
+ }
+
+ /**
+ * Returns the encoder.
+ *
+ * @return <code>MessageEncoder</code>
+ */
+ public MessageEncoder<ServletResponse> getEncoder() {
+ return encoder;
+ }
+
+ /**
+ * Sets the attribute resolver.
+ *
+ * @param r <code>AttributeResolver</code>
+ */
+ public void setAttributeResolver(AttributeResolver r) {
+ resolver = r;
+ }
+
+ /**
+ * Returns the attribute resolver.
+ *
+ * @return <code>AttributeResolver</code>
+ */
+ public AttributeResolver getAttributeResolver() {
+ return resolver;
+ }
+
+ /**
+ * Sets the filter engine.
+ *
+ * @param e <code>FilterEngine</code>
+ */
+ public void setFilterEngine(FilteringEngine e) {
+ engine = e;
+ }
+
+ /**
+ * Returns the filter engine.
+ *
+ * @return <code>FilterEngine</code>
+ */
+ public FilteringEngine getFilteringEngine() {
+ return engine;
+ }
+
+ /**
+ * Returns the relying party configuration.
+ *
+ * @return Returns the relyingParty.
+ */
+ public RelyingPartyConfiguration getRelyingPartyConfiguration() {
+ return relyingPartyConfiguration;
+ }
+
+ /**
+ * Sets the relying party configuration.
+ *
+ * @param c The relyingParty to set.
+ */
+ public void setRelyingPartyConfiguration(RelyingPartyConfiguration c) {
+ relyingPartyConfiguration = c;
+ }
+
+ /**
+ * This decodes the attribute query message from the supplied request.
+ *
+ * @param request <code>ServletRequest</code>
+ * @return <code>SAMLObject</code>
+ * @throws BindingException if the request cannot be decoded
+ */
+ protected SAMLObject decodeMessage(ServletRequest request) throws BindingException {
+ // call decode method on decoder
+ decoder.setRequest(request);
+ decoder.decode();
+ if (log.isDebugEnabled()) {
+ log.debug("decoded servlet request");
+ }
+
+ // get SAMLMessage from the decoder
+ final SAMLObject message = decoder.getSAMLMessage();
+ if (log.isDebugEnabled()) {
+ log.debug("retrieved attribute query message from decoder: " + message);
+ }
+
+ return message;
+ }
+
+
+ /**
+ * This encodes the supplied response.
+ *
+ * @param response <code>SAMLObject</code>
+ * @throws BindingException if the response cannot be encoded
+ */
+ protected void encodeResponse(SAMLObject response) throws BindingException {
+ encoder.setSAMLMessage(response);
+ encoder.encode();
+ if (log.isDebugEnabled()) {
+ log.debug("encoded saml1 response");
+ }
+ }
+}
--- /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.saml1;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.ServletRequest;
+
+import org.apache.log4j.Logger;
+import org.opensaml.Configuration;
+import org.opensaml.common.SAMLObjectBuilder;
+import org.opensaml.saml1.core.AttributeDesignator;
+import org.opensaml.saml1.core.AttributeQuery;
+import org.opensaml.saml1.core.AttributeStatement;
+import org.opensaml.saml1.core.NameIdentifier;
+import org.opensaml.ws.security.SecurityPolicy;
+import org.opensaml.xml.XMLObjectBuilderFactory;
+
+import edu.internet2.middleware.shibboleth.common.attribute.Attribute;
+import edu.internet2.middleware.shibboleth.common.attribute.AttributeEncoder;
+import edu.internet2.middleware.shibboleth.common.attribute.SAML1AttributeAuthority;
+import edu.internet2.middleware.shibboleth.common.attribute.SAML1AttributeEncoder;
+import edu.internet2.middleware.shibboleth.common.attribute.filtering.BasicFilterContext;
+import edu.internet2.middleware.shibboleth.common.attribute.filtering.FilteringEngine;
+import edu.internet2.middleware.shibboleth.common.attribute.filtering.FilteringException;
+import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException;
+import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolver;
+import edu.internet2.middleware.shibboleth.common.attribute.resolver.ResolutionContext;
+import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
+
+/**
+ * SAML 1 Attribute Authority.
+ */
+public class AttributeAuthority implements SAML1AttributeAuthority {
+
+ /** Class logger. */
+ private static Logger log = Logger.getLogger(AttributeAuthority.class);
+
+ /** For building XML objects. */
+ private XMLObjectBuilderFactory builderFactory;
+
+ /** Attribute resolver. */
+ private AttributeResolver attributeResolver;
+
+ /** Security policy. */
+ private SecurityPolicy securityPolicy;
+
+ /** Relying party configuration. */
+ private RelyingPartyConfiguration relyingPartyConfiguration;
+
+ /** To determine releasable attributes. */
+ private FilteringEngine filteringEngine;
+
+ /** Servlet request containing the SAML message. */
+ private ServletRequest request;
+
+ /**
+ * Default constructor.
+ */
+ public AttributeAuthority() {
+ builderFactory = Configuration.getBuilderFactory();
+ }
+
+ /**
+ * Gets the attribute resolver.
+ *
+ * @return Returns the attributeResolver.
+ */
+ public AttributeResolver getAttributeResolver() {
+ return attributeResolver;
+ }
+
+ /**
+ * Sets the attribute resolver.
+ *
+ * @param ar The attributeResolver to set.
+ */
+ public void setAttributeResolver(AttributeResolver ar) {
+ this.attributeResolver = ar;
+ }
+
+ /**
+ * Gets the request.
+ *
+ * @return Returns the request.
+ */
+ public ServletRequest getRequest() {
+ return request;
+ }
+
+ /**
+ * Sets the request.
+ *
+ * @param r The request to set.
+ */
+ public void setRequest(ServletRequest r) {
+ this.request = r;
+ }
+
+ /**
+ * Gets the filtering engine.
+ *
+ * @return Returns the filteringEngine.
+ */
+ public FilteringEngine getFilteringEngine() {
+ return filteringEngine;
+ }
+
+ /**
+ * Sets the filtering engine.
+ *
+ * @param fe The filteringEngine to set.
+ */
+ public void setFilteringEngine(FilteringEngine fe) {
+ this.filteringEngine = fe;
+ }
+
+ /**
+ * Gets the relying party configuration.
+ *
+ * @return Returns the relyingPartyConfiguration.
+ */
+ public RelyingPartyConfiguration getRelyingPartyConfiguration() {
+ return relyingPartyConfiguration;
+ }
+
+ /**
+ * Sets the relying party configuration.
+ *
+ * @param rpc The relyingPartyConfiguration to set.
+ */
+ public void setRelyingPartyConfiguration(RelyingPartyConfiguration rpc) {
+ this.relyingPartyConfiguration = rpc;
+ }
+
+ /**
+ * Gets the security policy.
+ *
+ * @return Returns the securityPolicy.
+ */
+ public SecurityPolicy getSecurityPolicy() {
+ return securityPolicy;
+ }
+
+ /**
+ * Sets the security policy.
+ *
+ * @param sp The securityPolicy to set.
+ */
+ public void setSecurityPolicy(SecurityPolicy sp) {
+ this.securityPolicy = sp;
+ }
+
+ /** {@inheritDoc} */
+ public AttributeStatement performAttributeQuery(AttributeQuery query) throws AttributeResolutionException,
+ FilteringException {
+ // get attributes from the message
+ Set<String> releasedAttributes = getMessageAttributes(query.getAttributeDesignators());
+
+ // create resolution context from the resolver, using nameid element from the attribute query
+ ResolutionContext resolutionContext = attributeResolver.createResolutionContext(query.getSubject()
+ .getNameIdentifier().getNameIdentifier(), securityPolicy.getIssuer().toString(), request);
+ // get resolved attributes from the resolver
+ Map<String, Attribute> resolvedAttributes = getResolvedAttributes(resolutionContext, releasedAttributes);
+
+ // filter attributes
+ BasicFilterContext filterContext = new BasicFilterContext(query.getSubject().getNameIdentifier()
+ .getNameIdentifier(), relyingPartyConfiguration.getProviderID(), query.getSubject().getNameIdentifier()
+ .getNameIdentifier(), resolvedAttributes);
+ Set<Attribute> filteredAttributes = filteringEngine.filterAttributes(filterContext);
+
+ // encode attributes
+ List<org.opensaml.saml1.core.Attribute> encodedAttributes = encodeAttributes(filteredAttributes);
+
+ // return attribute statement
+ return buildAttributeStatement(encodedAttributes);
+ }
+
+ /** {@inheritDoc} */
+ public AttributeStatement performAttributeQuery(String entity, NameIdentifier subject) {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public String getAttributeIDBySAMLAttribute(AttributeDesignator attribute) {
+ return attribute.getAttributeName();
+ }
+
+ /** {@inheritDoc} */
+ public AttributeDesignator getSAMLAttributeByAttributeID(String id) {
+ SAMLObjectBuilder<AttributeDesignator> attributeBuilder = (SAMLObjectBuilder<AttributeDesignator>) builderFactory
+ .getBuilder(AttributeDesignator.DEFAULT_ELEMENT_NAME);
+ AttributeDesignator attribute = attributeBuilder.buildObject();
+ attribute.setAttributeName(id);
+ return attribute;
+ }
+
+ /**
+ * This parses the attribute name from the supplied list of attribute designators.
+ *
+ * @param messageAttributes <code>List</code>
+ * @return <code>Set</code>
+ */
+ private Set<String> getMessageAttributes(List<AttributeDesignator> messageAttributes) {
+ final Set<String> attributes = new HashSet<String>(messageAttributes.size());
+ for (AttributeDesignator a : messageAttributes) {
+ attributes.add(getAttributeIDBySAMLAttribute(a));
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("message contains the following attributes: " + attributes);
+ }
+ return attributes;
+ }
+
+ /**
+ * This resolves the supplied attribute names using the supplied resolution context.
+ *
+ * @param context <code>ResolutionContext</code>
+ * @param releasedAttributes <code>Set</code>
+ * @return <code>Map</code> of attribute ID to attribute
+ * @throws AttributeResolutionException if an attribute cannot be resolved
+ */
+ private Map<String, Attribute> getResolvedAttributes(ResolutionContext context, Set<String> releasedAttributes)
+ throws AttributeResolutionException {
+ // call Attribute resolver
+ Set<Attribute> resolvedAttributes = getAttributeResolver().resolveAttributes(releasedAttributes, context);
+ if (log.isDebugEnabled()) {
+ log.debug("attribute resolver resolved the following attributes: " + resolvedAttributes);
+ }
+
+ Map<String, Attribute> attrs = new HashMap<String, Attribute>();
+ for (Attribute attr : resolvedAttributes) {
+ attrs.put(attr.getId(), attr);
+ }
+ return attrs;
+ }
+
+ /**
+ * This encodes the supplied list of attributes with that attribute's SAML1 encoder.
+ *
+ * @param resolvedAttributes <code>Set</code>
+ * @return <code>List</code> of core attributes
+ */
+ private List<org.opensaml.saml1.core.Attribute> encodeAttributes(Set<Attribute> resolvedAttributes) {
+ // encode attributes
+ List<org.opensaml.saml1.core.Attribute> encodedAttributes = new ArrayList<org.opensaml.saml1.core.Attribute>();
+
+ for (Attribute attr : resolvedAttributes) {
+ AttributeEncoder<org.opensaml.saml1.core.Attribute> enc = attr
+ .getEncoderByCategory(SAML1AttributeEncoder.CATEGORY);
+ encodedAttributes.add(enc.encode(attr));
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("attribute encoder encoded the following attributes: " + encodedAttributes);
+ }
+ return encodedAttributes;
+ }
+
+ /**
+ * This builds the attribute statement for this SAML request.
+ *
+ * @param encodedAttributes <code>List</code> of attributes
+ * @return <code>AttributeStatement</code>
+ */
+ private AttributeStatement buildAttributeStatement(List<org.opensaml.saml1.core.Attribute> encodedAttributes) {
+ SAMLObjectBuilder<AttributeStatement> statementBuilder = (SAMLObjectBuilder<AttributeStatement>) builderFactory
+ .getBuilder(AttributeStatement.DEFAULT_ELEMENT_NAME);
+ AttributeStatement statement = statementBuilder.buildObject();
+ statement.getAttributes().addAll(encodedAttributes);
+ return statement;
+ }
+}
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package edu.internet2.middleware.shibboleth.idp.profile.saml1;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
-import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
+import org.apache.log4j.Logger;
+import org.joda.time.DateTime;
+import org.opensaml.common.SAMLObjectBuilder;
+import org.opensaml.common.binding.BindingException;
+import org.opensaml.saml1.core.Advice;
+import org.opensaml.saml1.core.Assertion;
+import org.opensaml.saml1.core.AttributeStatement;
+import org.opensaml.saml1.core.Conditions;
+import org.opensaml.saml1.core.Response;
+import org.opensaml.saml1.core.Status;
+import org.opensaml.saml1.core.StatusCode;
+import org.opensaml.saml1.core.Subject;
+import org.opensaml.saml1.core.SubjectStatement;
+import org.opensaml.xml.encryption.EncryptionException;
+
+import edu.internet2.middleware.shibboleth.common.attribute.filtering.FilteringException;
+import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException;
/**
- * SAML 1 Attribute Query profile handler
+ * SAML 1 Attribute Query profile handler.
*/
-public class AttributeQuery implements ProfileHandler {
+public class AttributeQuery extends AbstractProfileHandler {
+
+ /** Class logger. */
+ private static Logger log = Logger.getLogger(AttributeQuery.class);
/** {@inheritDoc} */
public boolean processRequest(ServletRequest request, ServletResponse response) throws ServletException {
- // TODO Auto-generated method stub
- return false;
+ if (log.isDebugEnabled()) {
+ log.debug("begin processRequest");
+ }
+
+ // get message from the decoder
+ org.opensaml.saml1.core.AttributeQuery message = null;
+ try {
+ message = (org.opensaml.saml1.core.AttributeQuery) decodeMessage(request);
+ } catch (BindingException e) {
+ log.error("Error decoding attribute query message", e);
+ throw new ServletException("Error decoding attribute query message");
+ }
+
+ // get attribute statement from attribute authority
+ AttributeAuthority aa = new AttributeAuthority();
+ aa.setAttributeResolver(getAttributeResolver());
+ aa.setFilteringEngine(getFilteringEngine());
+ aa.setRelyingPartyConfiguration(getRelyingPartyConfiguration());
+ aa.setSecurityPolicy(getDecoder().getSecurityPolicy());
+ aa.setRequest(request);
+ AttributeStatement statement = null;
+ try {
+ statement = aa.performAttributeQuery(message);
+ } catch (AttributeResolutionException e) {
+ log.error("Error resolving attributes", e);
+ throw new ServletException("Error resolving attributes");
+ } catch (FilteringException e) {
+ log.error("Error filtering attributes", e);
+ throw new ServletException("Error filtering attributes");
+ }
+
+ // construct response
+ Response samlResponse = null;
+ try {
+ samlResponse = buildResponse(message, request.getRemoteHost(), new DateTime(), statement);
+ } catch (EncryptionException e) {
+ log.error("Error encrypting SAML response", e);
+ throw new ServletException("Error encrypting SAML response");
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("built saml1 response: " + samlResponse);
+ }
+
+ // encode response
+ try {
+ encodeResponse(samlResponse);
+ } catch (BindingException e) {
+ log.error("Error encoding attribute query response", e);
+ throw new ServletException("Error encoding attribute query response");
+ }
+
+ return true;
+ }
+
+ /**
+ * This builds the response for this SAML request.
+ *
+ * @param message <code>AttributeQuery</code>
+ * @param dest <code>String</code>
+ * @param issueInstant <code>DateTime</code>
+ * @param statement <code>AttributeStatement</code>
+ * @return <code>Response</code>
+ * @throws EncryptionException if an error occurs attempting to encrypt data
+ */
+ private Response buildResponse(org.opensaml.saml1.core.AttributeQuery message, String dest, DateTime issueInstant,
+ AttributeStatement statement) throws EncryptionException {
+ SAMLObjectBuilder<Response> responseBuilder = (SAMLObjectBuilder<Response>) getBuilderFactory().getBuilder(
+ Response.DEFAULT_ELEMENT_NAME);
+ /*
+ * required: samlp:Status, ID, Version, IssueInstant
+ */
+ Response response = responseBuilder.buildObject();
+ response.setVersion(SAML_VERSION);
+ response.setID(getIdGenerator().generateIdentifier());
+ response.setInResponseTo(getDecoder().getSecurityPolicy().getIssuer().toString());
+ response.setIssueInstant(issueInstant);
+ response.setRecipient(dest);
+
+ response.setStatus(buildStatus());
+ response.getAssertions().add(buildAssertion(message.getSubject(), issueInstant, statement));
+ return response;
+ }
+
+ /**
+ * This builds the status response for this SAML request.
+ *
+ * @return <code>Status</code>
+ */
+ private Status buildStatus() {
+ // build status
+ SAMLObjectBuilder<Status> statusBuilder = (SAMLObjectBuilder<Status>) getBuilderFactory().getBuilder(
+ Status.DEFAULT_ELEMENT_NAME);
+ Status status = statusBuilder.buildObject();
+
+ // build status code
+ SAMLObjectBuilder<StatusCode> statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory()
+ .getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
+ StatusCode statusCode = statusCodeBuilder.buildObject();
+ statusCode.setValue("Success");
+ status.setStatusCode(statusCode);
+ return status;
+ }
+
+ /**
+ * This builds the assertion for this SAML request.
+ *
+ * @param messageSubject <code>Subject</code>
+ * @param issueInstant <code>DateTime</code>
+ * @param statement <code>AttributeStatement</code> of attributes
+ * @return <code>Assertion</code>
+ * @throws EncryptionException if an error occurs attempting to encrypt data
+ */
+ private Assertion buildAssertion(Subject messageSubject, DateTime issueInstant, AttributeStatement statement)
+ throws EncryptionException {
+ // build assertion
+ SAMLObjectBuilder<Assertion> assertionBuilder = (SAMLObjectBuilder<Assertion>) getBuilderFactory().getBuilder(
+ Assertion.DEFAULT_ELEMENT_NAME);
+ /*
+ * required: saml:Issuer, ID, Version, IssueInstant
+ */
+ Assertion assertion = assertionBuilder.buildObject();
+ assertion.setID(getIdGenerator().generateIdentifier());
+ assertion.setIssueInstant(issueInstant);
+ assertion.setVersion(SAML_VERSION);
+ assertion.setIssuer(getRelyingPartyConfiguration().getProviderID());
+
+ // build subject
+ assertion.getSubjectStatements().add(buildSubjectStatement(messageSubject));
+ // build conditions
+ assertion.setConditions(buildConditions(issueInstant));
+ // build advice
+ assertion.setAdvice(buildAdvice());
+ // add attribute statement
+ assertion.getAttributeStatements().add(statement);
+ return assertion;
+ }
+
+ /**
+ * This builds the subject statement for this SAML request.
+ *
+ * @param messageSubject <code>Subject</code>
+ * @return <code>SubjectStatement</code>
+ */
+ private SubjectStatement buildSubjectStatement(Subject messageSubject) {
+ // build subject
+ SAMLObjectBuilder<SubjectStatement> subjectStatementBuilder = (SAMLObjectBuilder<SubjectStatement>) getBuilderFactory()
+ .getBuilder(SubjectStatement.DEFAULT_ELEMENT_NAME);
+ SubjectStatement subjectStatement = subjectStatementBuilder.buildObject();
+ subjectStatement.setSubject(messageSubject);
+ return subjectStatement;
+ }
+
+ /**
+ * This builds the conditions for this SAML request.
+ *
+ * @param issueInstant <code>DateTime</code>
+ * @return <code>Conditions</code>
+ */
+ private Conditions buildConditions(DateTime issueInstant) {
+ SAMLObjectBuilder<Conditions> conditionsBuilder = (SAMLObjectBuilder<Conditions>) getBuilderFactory()
+ .getBuilder(Conditions.DEFAULT_ELEMENT_NAME);
+ Conditions conditions = conditionsBuilder.buildObject();
+ conditions.setNotBefore(issueInstant);
+ // TODO conditions.setNotOnOrAfter();
+ // TODO add additional conditions : conditions.getConditions().add(Condition);
+ // TODO what about AudienceRestriction, OneTimeUse, ProxyRestriction?
+ return conditions;
+ }
+
+ /**
+ * This builds the advice for this SAML request.
+ *
+ * @return <code>Advice</code>
+ */
+ private Advice buildAdvice() {
+ SAMLObjectBuilder<Advice> adviceBuilder = (SAMLObjectBuilder<Advice>) getBuilderFactory().getBuilder(
+ Advice.DEFAULT_ELEMENT_NAME);
+ Advice advice = adviceBuilder.buildObject();
+ // advice.getAssertionIDReferences().add();
+ // advice.getAssertionURIReferences().add();
+ // advice.getAssertions().add();
+ // advice.getEncryptedAssertions().add();
+ // advice.addNamespace(namespace);
+ return advice;
}
}
\ No newline at end of file
package edu.internet2.middleware.shibboleth.idp.profile.saml2;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.log4j.Logger;
import org.opensaml.Configuration;
+import org.opensaml.common.SAMLObject;
+import org.opensaml.common.SAMLVersion;
+import org.opensaml.common.binding.BindingException;
import org.opensaml.common.binding.MessageDecoder;
import org.opensaml.common.binding.MessageEncoder;
+import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
+import org.opensaml.saml2.encryption.Encrypter;
import org.opensaml.saml2.metadata.provider.MetadataProvider;
import org.opensaml.xml.XMLObjectBuilderFactory;
-import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
+
import edu.internet2.middleware.shibboleth.common.attribute.filtering.FilteringEngine;
import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolver;
import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
+import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
/**
* Common implementation details for profile handlers.
*/
public abstract class AbstractProfileHandler implements ProfileHandler {
- /** For building XML objects. */
+ /** SAML Version for this profile handler. */
+ public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_20;
+
+ /** Class logger. */
+ private static Logger log = Logger.getLogger(AbstractProfileHandler.class);
+
+ /** For building XML. */
private XMLObjectBuilderFactory builderFactory;
-
- /** For generating secure random ids. */
- private SecureRandomIdentifierGenerator idGenerator;
+
+ /** For generating random ids. */
+ private SecureRandomIdentifierGenerator idGenerator;
/** For decoding requests. */
- private MessageDecoder decoder;
+ private MessageDecoder<ServletRequest> decoder;
/** For encoding responses. */
- private MessageEncoder encoder;
+ private MessageEncoder<ServletResponse> encoder;
+
+ /** Relying party configuration. */
+ private RelyingPartyConfiguration relyingPartyConfiguration;
/** For resolving attributes. */
private AttributeResolver resolver;
-
+
/** To determine releasable attributes. */
private FilteringEngine engine;
-
- /** */
+
+ /** Attribute metadata provider. */
private MetadataProvider provider;
-
-
+
+ /** For encrypting XML. */
+ private Encrypter encrypter;
+
/**
* Default constructor.
*/
public AbstractProfileHandler() {
builderFactory = Configuration.getBuilderFactory();
- idGenerator = new SecureRandomIdentifierGenerator();
- }
-
-
- /**
- * Sets the builder factory.
- *
- * @param f <code>XMLObjectBuilderFactory</code>
- */
- public void setBuilderFactory(XMLObjectBuilderFactory f) {
- builderFactory = f;
+ idGenerator = new SecureRandomIdentifierGenerator();
}
-
/**
- * Returns the builder factory.
+ * Returns the XML builder factory.
*
- * @return <code>XMLObjectBuilderFactory</code>
+ * @return Returns the builderFactory.
*/
public XMLObjectBuilderFactory getBuilderFactory() {
- return builderFactory;
- }
-
-
- /**
- * Sets the id generator.
- *
- * @param g <code>SecureRandomIdentifierGenerator</code>
- */
- public void setIdGenerator(SecureRandomIdentifierGenerator g) {
- idGenerator = g;
+ return builderFactory;
}
-
/**
* Returns the id generator.
*
- * @return <code>SecureRandomIdentifierGenerator</code>
+ * @return Returns the idGenerator.
*/
public SecureRandomIdentifierGenerator getIdGenerator() {
- return idGenerator;
+ return idGenerator;
}
-
/**
* Sets the decoder.
*
- * @param d <code>MessageDecoder</code>
+ * @param d <code>MessageDecoder</code>
*/
- public void setDecoder(MessageDecoder d) {
- decoder = d;
+ public void setDecoder(MessageDecoder<ServletRequest> d) {
+ decoder = d;
}
-
/**
* Returns the decoder.
*
- * @return <code>MessageDecoder</code>
+ * @return <code>MessageDecoder</code>
*/
- public MessageDecoder getDecoder() {
- return decoder;
+ public MessageDecoder<ServletRequest> getDecoder() {
+ return decoder;
}
-
/**
* Sets the encoder.
*
- * @param e <code>MessageEncoder</code>
+ * @param e <code>MessageEncoder</code>
*/
- public void setEncoder(MessageEncoder e) {
- encoder = e;
+ public void setEncoder(MessageEncoder<ServletResponse> e) {
+ encoder = e;
}
-
-
+
/**
* Returns the encoder.
*
- * @return <code>MessageEncoder</code>
+ * @return <code>MessageEncoder</code>
*/
- public MessageEncoder getEncoder() {
- return encoder;
+ public MessageEncoder<ServletResponse> getEncoder() {
+ return encoder;
}
-
/**
* Sets the attribute resolver.
*
- * @param r <code>AttributeResolver</code>
+ * @param r <code>AttributeResolver</code>
*/
public void setAttributeResolver(AttributeResolver r) {
- resolver = r;
+ resolver = r;
}
-
/**
* Returns the attribute resolver.
*
- * @return <code>AttributeResolver</code>
- */
+ * @return <code>AttributeResolver</code>
+ */
public AttributeResolver getAttributeResolver() {
- return resolver;
+ return resolver;
}
-
/**
* Sets the filter engine.
*
- * @param e <code>FilterEngine</code>
+ * @param e <code>FilterEngine</code>
*/
public void setFilterEngine(FilteringEngine e) {
- engine = e;
+ engine = e;
}
-
-
+
/**
* Returns the filter engine.
*
- * @return <code>FilterEngine</code>
- */
- public FilteringEngine getFilterEngine() {
- return engine;
+ * @return <code>FilterEngine</code>
+ */
+ public FilteringEngine getFilteringEngine() {
+ return engine;
}
-
/**
* Sets the metadata provider.
*
- * @param p <code>MetadataProvider</code>
+ * @param p <code>MetadataProvider</code>
*/
public void setMetadataProvider(MetadataProvider p) {
- provider = p;
+ provider = p;
}
-
/**
* Returns the metadata provider.
*
- * @return <code>MetadataProvider</code>
- */
+ * @return <code>MetadataProvider</code>
+ */
public MetadataProvider getMetadataProvider() {
- return provider;
+ return provider;
+ }
+
+ /**
+ * Returns the relying party configuration.
+ *
+ * @return Returns the relyingParty.
+ */
+ public RelyingPartyConfiguration getRelyingPartyConfiguration() {
+ return relyingPartyConfiguration;
+ }
+
+ /**
+ * Sets the relying party configuration.
+ *
+ * @param c The relyingParty to set.
+ */
+ public void setRelyingPartyConfiguration(RelyingPartyConfiguration c) {
+ relyingPartyConfiguration = c;
+ }
+
+ /**
+ * Returns the encrypter.
+ *
+ * @return Returns the encrypter.
+ */
+ public Encrypter getEncrypter() {
+ return encrypter;
+ }
+
+ /**
+ * Sets the encrypter.
+ *
+ * @param e The encrypter to set.
+ */
+ public void setEncrypter(Encrypter e) {
+ encrypter = e;
+ }
+
+ /**
+ * This decodes the attribute query message from the supplied request.
+ *
+ * @param request <code>ServletRequest</code>
+ * @return <code>SAMLObject</code>
+ * @throws BindingException if the request cannot be decoded
+ */
+ protected SAMLObject decodeMessage(ServletRequest request) throws BindingException {
+ // call decode method on decoder
+ decoder.setRequest(request);
+ decoder.decode();
+ if (log.isDebugEnabled()) {
+ log.debug("decoded servlet request");
+ }
+
+ // get SAMLMessage from the decoder
+ final SAMLObject message = decoder.getSAMLMessage();
+ if (log.isDebugEnabled()) {
+ log.debug("retrieved attribute query message from decoder: " + message);
+ }
+
+ return message;
+ }
+
+ /**
+ * This encodes the supplied response.
+ *
+ * @param response <code>SAMLObject</code>
+ * @throws BindingException if the response cannot be encoded
+ */
+ protected void encodeResponse(SAMLObject response) throws BindingException {
+ encoder.setSAMLMessage(response);
+ encoder.encode();
+ if (log.isDebugEnabled()) {
+ log.debug("encoded saml1 response");
+ }
}
}
--- /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 java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.ServletRequest;
+
+import org.apache.log4j.Logger;
+import org.opensaml.Configuration;
+import org.opensaml.common.SAMLObjectBuilder;
+import org.opensaml.saml2.core.AttributeQuery;
+import org.opensaml.saml2.core.AttributeStatement;
+import org.opensaml.saml2.core.NameID;
+import org.opensaml.ws.security.SecurityPolicy;
+import org.opensaml.xml.XMLObjectBuilderFactory;
+
+import edu.internet2.middleware.shibboleth.common.attribute.Attribute;
+import edu.internet2.middleware.shibboleth.common.attribute.AttributeEncoder;
+import edu.internet2.middleware.shibboleth.common.attribute.SAML2AttributeAuthority;
+import edu.internet2.middleware.shibboleth.common.attribute.SAML2AttributeEncoder;
+import edu.internet2.middleware.shibboleth.common.attribute.filtering.BasicFilterContext;
+import edu.internet2.middleware.shibboleth.common.attribute.filtering.FilteringEngine;
+import edu.internet2.middleware.shibboleth.common.attribute.filtering.FilteringException;
+import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException;
+import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolver;
+import edu.internet2.middleware.shibboleth.common.attribute.resolver.ResolutionContext;
+import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
+
+/**
+ * SAML 2.0 Attribute Authority.
+ */
+public class AttributeAuthority implements SAML2AttributeAuthority {
+
+ /** Class logger. */
+ private static Logger log = Logger.getLogger(AttributeAuthority.class);
+
+ /** For building XML objects. */
+ private XMLObjectBuilderFactory builderFactory;
+
+ /** Attribute resolver. */
+ private AttributeResolver attributeResolver;
+
+ /** Security policy. */
+ private SecurityPolicy securityPolicy;
+
+ /** Relying party configuration. */
+ private RelyingPartyConfiguration relyingPartyConfiguration;
+
+ /** To determine releasable attributes. */
+ private FilteringEngine filteringEngine;
+
+ /** Servlet request containing the SAML message. */
+ private ServletRequest request;
+
+ /**
+ * Default constructor.
+ */
+ public AttributeAuthority() {
+ builderFactory = Configuration.getBuilderFactory();
+ }
+
+ /**
+ * Gets the attribute resolver.
+ *
+ * @return Returns the attributeResolver.
+ */
+ public AttributeResolver getAttributeResolver() {
+ return attributeResolver;
+ }
+
+ /**
+ * Sets the attribute resolver.
+ *
+ * @param ar The attributeResolver to set.
+ */
+ public void setAttributeResolver(AttributeResolver ar) {
+ this.attributeResolver = ar;
+ }
+
+ /**
+ * Gets the request.
+ *
+ * @return Returns the request.
+ */
+ public ServletRequest getRequest() {
+ return request;
+ }
+
+ /**
+ * Sets the request.
+ *
+ * @param r The request to set.
+ */
+ public void setRequest(ServletRequest r) {
+ this.request = r;
+ }
+
+ /**
+ * Gets the filtering engine.
+ *
+ * @return Returns the filteringEngine.
+ */
+ public FilteringEngine getFilteringEngine() {
+ return filteringEngine;
+ }
+
+ /**
+ * Sets the filtering engine.
+ *
+ * @param fe The filteringEngine to set.
+ */
+ public void setFilteringEngine(FilteringEngine fe) {
+ this.filteringEngine = fe;
+ }
+
+ /**
+ * Gets the relying party configuration.
+ *
+ * @return Returns the relyingPartyConfiguration.
+ */
+ public RelyingPartyConfiguration getRelyingPartyConfiguration() {
+ return relyingPartyConfiguration;
+ }
+
+ /**
+ * Sets the relying party configuration.
+ *
+ * @param rpc The relyingPartyConfiguration to set.
+ */
+ public void setRelyingPartyConfiguration(RelyingPartyConfiguration rpc) {
+ this.relyingPartyConfiguration = rpc;
+ }
+
+ /**
+ * Gets the security policy.
+ *
+ * @return Returns the securityPolicy.
+ */
+ public SecurityPolicy getSecurityPolicy() {
+ return securityPolicy;
+ }
+
+ /**
+ * Sets the security policy.
+ *
+ * @param sp The securityPolicy to set.
+ */
+ public void setSecurityPolicy(SecurityPolicy sp) {
+ this.securityPolicy = sp;
+ }
+
+ /** {@inheritDoc} */
+ public AttributeStatement performAttributeQuery(AttributeQuery query) throws AttributeResolutionException,
+ FilteringException {
+ // get attributes from the message
+ Set<String> releasedAttributes = getMessageAttributes(query.getAttributes());
+
+ // create resolution context from the resolver, using nameid element from the attribute query
+ ResolutionContext resolutionContext = getAttributeResolver().createResolutionContext(
+ query.getSubject().getNameID(), securityPolicy.getIssuer().toString(), request);
+ // get resolved attributes from the resolver
+ Map<String, Attribute> resolvedAttributes = getResolvedAttributes(resolutionContext, releasedAttributes);
+
+ // filter attributes
+ BasicFilterContext filteringContext = new BasicFilterContext(query.getSubject().getNameID().toString(),
+ getRelyingPartyConfiguration().getProviderID(), query.getSubject().getNameID().toString(),
+ resolvedAttributes);
+ Set<Attribute> filteredAttributes = filteringEngine.filterAttributes(filteringContext);
+
+ // encode attributes
+ List<org.opensaml.saml2.core.Attribute> encodedAttributes = encodeAttributes(filteredAttributes);
+
+ // return attribute statement
+ return buildAttributeStatement(encodedAttributes);
+ }
+
+ /** {@inheritDoc} */
+ public AttributeStatement performAttributeQuery(String entity, NameID subject) throws AttributeResolutionException,
+ FilteringException {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public String getAttributeIDBySAMLAttribute(org.opensaml.saml2.core.Attribute attribute) {
+ return attribute.getName();
+ }
+
+ /** {@inheritDoc} */
+ public org.opensaml.saml2.core.Attribute getSAMLAttributeByAttributeID(String id) {
+ SAMLObjectBuilder<org.opensaml.saml2.core.Attribute> attributeBuilder = (SAMLObjectBuilder<org.opensaml.saml2.core.Attribute>) builderFactory
+ .getBuilder(org.opensaml.saml2.core.Attribute.DEFAULT_ELEMENT_NAME);
+ org.opensaml.saml2.core.Attribute attribute = attributeBuilder.buildObject();
+ attribute.setName(id);
+ return attribute;
+ }
+
+ /**
+ * This parses the attribute name from the supplied list of attributes.
+ *
+ * @param messageAttributes <code>List</code>
+ * @return <code>Set</code>
+ */
+ private Set<String> getMessageAttributes(List<org.opensaml.saml2.core.Attribute> messageAttributes) {
+ final Set<String> attributes = new HashSet<String>(messageAttributes.size());
+ for (org.opensaml.saml2.core.Attribute a : messageAttributes) {
+ attributes.add(getAttributeIDBySAMLAttribute(a));
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("message contains the following attributes: " + attributes);
+ }
+ // TODO go to metadata for other attributes
+ return attributes;
+ }
+
+ /**
+ * This resolves the supplied attribute names using the supplied resolution context.
+ *
+ * @param context <code>ResolutionContext</code>
+ * @param releasedAttributes <code>Set</code>
+ * @return <code>Map</code> of attribute ID to attribute
+ * @throws AttributeResolutionException if an attribute cannot be resolved
+ */
+ private Map<String, Attribute> getResolvedAttributes(ResolutionContext context, Set<String> releasedAttributes)
+ throws AttributeResolutionException {
+ // call Attribute resolver
+ Set<Attribute> resolvedAttributes = getAttributeResolver().resolveAttributes(releasedAttributes, context);
+ if (log.isDebugEnabled()) {
+ log.debug("attribute resolver resolved the following attributes: " + resolvedAttributes);
+ }
+
+ Map<String, Attribute> attrs = new HashMap<String, Attribute>();
+ for (Attribute attr : resolvedAttributes) {
+ attrs.put(attr.getId(), attr);
+ }
+ return attrs;
+ }
+
+ /**
+ * This encodes the supplied list of attributes with that attribute's SAML2 encoder.
+ *
+ * @param resolvedAttributes <code>Set</code>
+ * @return <code>List</code> of core attributes
+ */
+ private List<org.opensaml.saml2.core.Attribute> encodeAttributes(Set<Attribute> resolvedAttributes) {
+ // encode attributes
+ List<org.opensaml.saml2.core.Attribute> encodedAttributes = new ArrayList<org.opensaml.saml2.core.Attribute>();
+
+ for (Attribute attr : resolvedAttributes) {
+ AttributeEncoder<org.opensaml.saml2.core.Attribute> enc = attr
+ .getEncoderByCategory(SAML2AttributeEncoder.CATEGORY);
+ encodedAttributes.add(enc.encode(attr));
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("attribute encoder encoded the following attributes: " + encodedAttributes);
+ }
+ return encodedAttributes;
+ }
+
+ /**
+ * This builds the attribute statement for this SAML request.
+ *
+ * @param encodedAttributes <code>List</code> of attributes
+ * @return <code>AttributeStatement</code>
+ */
+ private AttributeStatement buildAttributeStatement(List<org.opensaml.saml2.core.Attribute> encodedAttributes) {
+ SAMLObjectBuilder<AttributeStatement> statementBuilder = (SAMLObjectBuilder<AttributeStatement>) builderFactory
+ .getBuilder(AttributeStatement.DEFAULT_ELEMENT_NAME);
+ AttributeStatement statement = statementBuilder.buildObject();
+ statement.getAttributes().addAll(encodedAttributes);
+ return statement;
+ }
+}
* 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.List;
-import java.util.HashSet;
-import java.util.Set;
+package edu.internet2.middleware.shibboleth.idp.profile.saml2;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
-import edu.internet2.middleware.shibboleth.common.attribute.Attribute;
-import edu.internet2.middleware.shibboleth.common.attribute.AttributeEncoder;
-import edu.internet2.middleware.shibboleth.common.attribute.SAML2AttributeEncoder;
-import edu.internet2.middleware.shibboleth.common.attribute.resolver.ResolutionContext;
-import edu.internet2.middleware.shibboleth.idp.profile.AbstractProfileHandler;
-
+import org.apache.log4j.Logger;
import org.joda.time.DateTime;
-
import org.opensaml.common.SAMLObjectBuilder;
-import org.opensaml.common.SAMLVersion;
-
+import org.opensaml.common.binding.BindingException;
+import org.opensaml.saml2.core.Advice;
import org.opensaml.saml2.core.Assertion;
import org.opensaml.saml2.core.AttributeStatement;
import org.opensaml.saml2.core.Conditions;
+import org.opensaml.saml2.core.Issuer;
import org.opensaml.saml2.core.Response;
import org.opensaml.saml2.core.Status;
import org.opensaml.saml2.core.StatusCode;
import org.opensaml.saml2.core.Subject;
+import org.opensaml.xml.encryption.EncryptionException;
+
+import edu.internet2.middleware.shibboleth.common.attribute.filtering.FilteringException;
+import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException;
/**
* SAML 2.0 Attribute Query profile handler.
*/
public class AttributeQuery extends AbstractProfileHandler {
- /** SAML Version for this profile handler. */
- public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_20;
-
-
+ /** Class logger. */
+ private static Logger log = Logger.getLogger(AttributeQuery.class);
+
/** {@inheritDoc} */
public boolean processRequest(ServletRequest request, ServletResponse response) throws ServletException {
- // call decode method on decoder
- getDecoder().decode(request);
- // get SAMLMessage from the decoder
- final org.opensaml.saml2.core.AttributeQuery message =
- (org.opensaml.saml2.core.AttributeQuery) getDecoder().getSAMLMessage();
-
- // intersect requested attributes with released attributes
- final List<org.opensaml.saml2.core.Attribute> requestedAttributes = message.getAttributes();
- final Set<String> releasedAttributes = new HashSet<String>(requestedAttributes.size());
- for (org.opensaml.saml2.core.Attribute a: requestedAttributes) {
- releasedAttributes.add(a.getName());
+ if (log.isDebugEnabled()) {
+ log.debug("begin processRequest");
+ }
+
+ // get message from the decoder
+ org.opensaml.saml2.core.AttributeQuery message = null;
+ try {
+ message = (org.opensaml.saml2.core.AttributeQuery) decodeMessage(request);
+ } catch (BindingException e) {
+ log.error("Error decoding attribute query message", e);
+ throw new ServletException("Error decoding attribute query message");
}
- List<String> releaseableAttributes = getFilterEngine().getReleaseableAttributes(getDecoder().getIssuer());
- releasedAttributes.retainAll(releaseableAttributes);
- // TODO go to metadata for other attributes
-
- // create resolution context from the resolver, using nameid element from the attribute query
- ResolutionContext context = getAttributeResolver().createResolutionContext(
- message.getSubject().getNameID(), getDecoder().getIssuer(), request);
- // call Attribute resolver
- Set<Attribute> resolvedAttributes = getAttributeResolver().resolveAttributes(releasedAttributes, context);
-
+
+ // get attribute statement from attribute authority
+ AttributeAuthority aa = new AttributeAuthority();
+ aa.setAttributeResolver(getAttributeResolver());
+ aa.setFilteringEngine(getFilteringEngine());
+ aa.setRelyingPartyConfiguration(getRelyingPartyConfiguration());
+ aa.setSecurityPolicy(getDecoder().getSecurityPolicy());
+ aa.setRequest(request);
+ AttributeStatement statement = null;
+ try {
+ statement = aa.performAttributeQuery(message);
+ } catch (AttributeResolutionException e) {
+ log.error("Error resolving attributes", e);
+ throw new ServletException("Error resolving attributes");
+ } catch (FilteringException e) {
+ log.error("Error filtering attributes", e);
+ throw new ServletException("Error filtering attributes");
+ }
+
// construct attribute response
- List<org.opensaml.saml2.core.Attribute> encodedAttributes = new ArrayList<org.opensaml.saml2.core.Attribute>();
- for (Attribute attr: resolvedAttributes) {
- AttributeEncoder enc = attr.getEncoderByCategory(org.opensaml.saml2.core.Attribute.URI_REFERENCE);
- encodedAttributes.add(enc.encode(attr));
+ Response samlResponse = null;
+ try {
+ samlResponse = buildResponse(message, request.getRemoteHost(), new DateTime(), statement);
+ } catch (EncryptionException e) {
+ log.error("Error encrypting SAML response", e);
+ throw new ServletException("Error encrypting SAML response");
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("built saml2 response: " + samlResponse);
+ }
+
+ try {
+ encodeResponse(samlResponse);
+ } catch (BindingException e) {
+ log.error("Error encoding attribute query response", e);
+ throw new ServletException("Error encoding attribute query response");
}
- Response samlResponse = buildResponse(getDecoder().getIssuer(), new DateTime(), encodedAttributes);
- getEncoder().setSAMLMessage(response);
- getEncoder().encode();
return true;
}
-
-
+
/**
* This builds the response for this SAML request.
*
- * @param issuer <code>String</code>
- * @param issueInstant <code>DateTime</code>
- * @param encodedAttributes <code>List</code> of attributes
- * @return <code>Response</code>
+ * @param message <code>AttributeQuery</code>
+ * @param dest <code>String</code>
+ * @param issueInstant <code>DateTime</code>
+ * @param statement <code>AttributeStatement</code> of attributes
+ * @return <code>Response</code>
+ * @throws EncryptionException if an error occurs attempting to encrypt data
*/
- private Response buildResponse(
- String issuer, DateTime issueInstant, List<org.opensaml.saml2.core.Attribute> encodedAttributes) {
+ public Response buildResponse(org.opensaml.saml2.core.AttributeQuery message, String dest, DateTime issueInstant,
+ AttributeStatement statement) throws EncryptionException {
SAMLObjectBuilder<Response> responseBuilder = (SAMLObjectBuilder<Response>) getBuilderFactory().getBuilder(
- Response.DEFAULT_ELEMENT_NAME);
+ Response.DEFAULT_ELEMENT_NAME);
+ /*
+ * required: samlp:Status, ID, Version, IssueInstant
+ */
Response response = responseBuilder.buildObject();
response.setVersion(SAML_VERSION);
response.setID(getIdGenerator().generateIdentifier());
- response.setInResponseTo(issuer);
+ response.setInResponseTo(getDecoder().getSecurityPolicy().getIssuer().toString());
response.setIssueInstant(issueInstant);
+ response.setDestination(dest);
+
+ response.setIssuer(buildIssuer());
+ // TODO set consent
+ /*
+ * if (consent != null) { response.setConsent(consent); }
+ */
+ // TODO set extensions
+ /*
+ * if (extensions != null) { response.setExtensions(extensions); }
+ */
- //response.setDestination(String);
- //response.setConsent(String);
- //response.setIssuer(Issuer);
- //response.setExtensions(Extensions);
-
response.setStatus(buildStatus());
- response.getAssertions().add(buildAssertion(issueInstant, encodedAttributes));
+ if (getRelyingPartyConfiguration().encryptAssertion()) {
+ response.getEncryptedAssertions().add(
+ getEncrypter().encrypt(buildAssertion(message.getSubject(), issueInstant, statement)));
+ } else {
+ response.getAssertions().add(buildAssertion(message.getSubject(), issueInstant, statement));
+ }
+ return response;
}
-
/**
* This builds the status response for this SAML request.
*
- * @return <code>Status</code>
+ * @return <code>Status</code>
*/
private Status buildStatus() {
// build status
Status status = statusBuilder.buildObject();
// build status code
- SAMLObjectBuilder statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory().getBuilder(
- StatusCode.DEFAULT_ELEMENT_NAME);
+ SAMLObjectBuilder<StatusCode> statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory()
+ .getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
StatusCode statusCode = statusCodeBuilder.buildObject();
statusCode.setValue(StatusCode.SUCCESS_URI);
status.setStatusCode(statusCode);
return status;
}
-
-
+
/**
* This builds the assertion for this SAML request.
*
- * @param issueInstant <code>DateTime</code>
- * @param encodedAttributes <code>List</code> of attributes
- * @return <code>Assertion</code>
+ * @param messageSubject <code>Subject</code>
+ * @param issueInstant <code>DateTime</code>
+ * @param statement <code>AttributeStatement</code> of attributes
+ * @return <code>Assertion</code>
+ * @throws EncryptionException if an error occurs attempting to encrypt data
*/
- private Assertion buildAssertion(DateTime issueInstant, List<org.opensaml.saml2.core.Attribute> encodedAttributes) {
+ private Assertion buildAssertion(Subject messageSubject, DateTime issueInstant, AttributeStatement statement)
+ throws EncryptionException {
// build assertions
- SAMLObjectBuilder assertionBuilder = (SAMLObjectBuilder<Assertion>) getBuilderFactory().getBuilder(
+ SAMLObjectBuilder<Assertion> assertionBuilder = (SAMLObjectBuilder<Assertion>) getBuilderFactory().getBuilder(
Assertion.DEFAULT_ELEMENT_NAME);
+ /*
+ * required: saml:Issuer, ID, Version, IssueInstant
+ */
Assertion assertion = assertionBuilder.buildObject();
assertion.setID(getIdGenerator().generateIdentifier());
assertion.setIssueInstant(issueInstant);
assertion.setVersion(SAML_VERSION);
- // TODO assertion.setIssuer();
+ assertion.setIssuer(buildIssuer());
// build subject
- SAMLObjectBuilder subjectBuilder = (SAMLObjectBuilder<Subject>) getBuilderFactory().getBuilder(
+ assertion.setSubject(buildSubject(messageSubject));
+ // build conditions
+ assertion.setConditions(buildConditions(issueInstant));
+ // build advice
+ assertion.setAdvice(buildAdvice());
+ // add attribute statement
+ assertion.getAttributeStatements().add(statement);
+ return assertion;
+ }
+
+ /**
+ * This builds the issuer response for this SAML request.
+ *
+ * @return <code>Issuer</code>
+ */
+ private Issuer buildIssuer() {
+ // build status
+ SAMLObjectBuilder<Issuer> issuerBuilder = (SAMLObjectBuilder<Issuer>) getBuilderFactory().getBuilder(
+ Issuer.DEFAULT_ELEMENT_NAME);
+ Issuer issuer = issuerBuilder.buildObject();
+ issuer.setValue(getRelyingPartyConfiguration().getProviderID());
+ return issuer;
+ }
+
+ /**
+ * This builds the subject for this SAML request.
+ *
+ * @param messageSubject <code>Subject</code>
+ * @return <code>Subject</code>
+ * @throws EncryptionException if encryption of the name id fails
+ */
+ private Subject buildSubject(Subject messageSubject) throws EncryptionException {
+ // build subject
+ SAMLObjectBuilder<Subject> subjectBuilder = (SAMLObjectBuilder<Subject>) getBuilderFactory().getBuilder(
Subject.DEFAULT_ELEMENT_NAME);
Subject subject = subjectBuilder.buildObject();
- // TOTO subject.setNameID(NameID); <- comes from request
- assertion.setSubject(subject);
+ if (getRelyingPartyConfiguration().encryptNameID()) {
+ subject.setEncryptedID(getEncrypter().encrypt(messageSubject.getNameID()));
+ } else {
+ subject.setNameID(messageSubject.getNameID());
+ // TODO when is subject.setBaseID(newBaseID) called, if ever?
+ }
+ return subject;
+ }
- // build conditions
- SAMLObjectBuilder conditionsBuilder = (SAMLObjectBuilder<Conditions>) getBuilderFactory().getBuilder(
- Conditions.DEFAULT_ELEMENT_NAME);
+ /**
+ * This builds the conditions for this SAML request.
+ *
+ * @param issueInstant <code>DateTime</code>
+ * @return <code>Conditions</code>
+ */
+ private Conditions buildConditions(DateTime issueInstant) {
+ SAMLObjectBuilder<Conditions> conditionsBuilder = (SAMLObjectBuilder<Conditions>) getBuilderFactory()
+ .getBuilder(Conditions.DEFAULT_ELEMENT_NAME);
Conditions conditions = conditionsBuilder.buildObject();
conditions.setNotBefore(issueInstant);
- //TODO conditions.setNotOnOrAfter();
- //TODO add additional conditions : conditions.getConditions().add(Condition);
- assertion.setConditions(conditions);
-
- // build attribute statement
- SAMLObjectBuilder statementBuilder = (SAMLObjectBuilder<AttributeStatement>) getBuilderFactory().getBuilder(
- AttributeStatement.DEFAULT_ELEMENT_NAME);
- AttributeStatement statement = statementBuilder.buildObject();
- statement.getAttributes().addAll(encodedAttributes);
- assertion.getAttributeStatements().add(statement);
-
- return assertion;
+ // TODO conditions.setNotOnOrAfter();
+ // TODO add additional conditions : conditions.getConditions().add(Condition);
+ // TODO what about AudienceRestriction, OneTimeUse, ProxyRestriction?
+ return conditions;
+ }
+
+ /**
+ * This builds the advice for this SAML request.
+ *
+ * @return <code>Advice</code>
+ */
+ private Advice buildAdvice() {
+ SAMLObjectBuilder<Advice> adviceBuilder = (SAMLObjectBuilder<Advice>) getBuilderFactory().getBuilder(
+ Advice.DEFAULT_ELEMENT_NAME);
+ Advice advice = adviceBuilder.buildObject();
+ // advice.getAssertionIDReferences().add();
+ // advice.getAssertionURIReferences().add();
+ // advice.getAssertions().add();
+ // advice.getEncryptedAssertions().add();
+ // advice.addNamespace(namespace);
+ return advice;
}
}
\ No newline at end of file