75938c8082e41189ca3b824674523d11860c5ebb
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / idp / profile / saml1 / AttributeQuery.java
1 /*
2  * Copyright [2006] [University Corporation for Advanced Internet Development, Inc.]
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package edu.internet2.middleware.shibboleth.idp.profile.saml1;
18
19 import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
20 import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
21
22 import javax.servlet.ServletException;
23
24 import org.apache.log4j.Logger;
25 import org.joda.time.DateTime;
26 import org.opensaml.common.SAMLObjectBuilder;
27 import org.opensaml.common.binding.BindingException;
28 import org.opensaml.saml1.core.Advice;
29 import org.opensaml.saml1.core.Assertion;
30 import org.opensaml.saml1.core.AttributeStatement;
31 import org.opensaml.saml1.core.Conditions;
32 import org.opensaml.saml1.core.Response;
33 import org.opensaml.saml1.core.Status;
34 import org.opensaml.saml1.core.StatusCode;
35 import org.opensaml.saml1.core.Subject;
36 import org.opensaml.saml1.core.SubjectStatement;
37 import org.opensaml.xml.encryption.EncryptionException;
38
39 import edu.internet2.middleware.shibboleth.common.attribute.filtering.AttributeFilteringException;
40 import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException;
41
42 /**
43  * SAML 1 Attribute Query profile handler.
44  */
45 public class AttributeQuery extends AbstractSAML1ProfileHandler {
46
47     /** Class logger. */
48     private static Logger log = Logger.getLogger(AttributeQuery.class);
49
50     /** {@inheritDoc} */
51     public boolean processRequest(ProfileRequest request, ProfileResponse response) throws ServletException {
52         if (log.isDebugEnabled()) {
53             log.debug("begin processRequest");
54         }
55
56         // get message from the decoder
57         org.opensaml.saml1.core.AttributeQuery message = null;
58         try {
59             message = (org.opensaml.saml1.core.AttributeQuery) decodeMessage(request);
60         } catch (BindingException e) {
61             log.error("Error decoding attribute query message", e);
62             throw new ServletException("Error decoding attribute query message");
63         }
64
65         // get attribute statement from attribute authority
66         AttributeAuthority aa = new AttributeAuthority();
67         aa.setAttributeResolver(getAttributeResolver());
68         aa.setFilteringEngine(getFilteringEngine());
69         aa.setRelyingPartyConfiguration(getRelyingPartyConfiguration());
70         aa.setSecurityPolicy(getDecoder().getSecurityPolicy());
71         aa.setRequest(request);
72         AttributeStatement statement = null;
73         try {
74             statement = aa.performAttributeQuery(message);
75         } catch (AttributeResolutionException e) {
76             log.error("Error resolving attributes", e);
77             throw new ServletException("Error resolving attributes");
78         } catch (FilteringException e) {
79             log.error("Error filtering attributes", e);
80             throw new ServletException("Error filtering attributes");
81         }
82
83         // construct response
84         Response samlResponse = null;
85         try {
86             samlResponse = buildResponse(message, request.getRemoteHost(), new DateTime(), statement);
87         } catch (EncryptionException e) {
88             log.error("Error encrypting SAML response", e);
89             throw new ServletException("Error encrypting SAML response");
90         }
91         if (log.isDebugEnabled()) {
92             log.debug("built saml1 response: " + samlResponse);
93         }
94
95         // encode response
96         try {
97             encodeResponse(samlResponse);
98         } catch (BindingException e) {
99             log.error("Error encoding attribute query response", e);
100             throw new ServletException("Error encoding attribute query response");
101         }
102
103         return true;
104     }
105
106     /**
107      * This builds the response for this SAML request.
108      * 
109      * @param message <code>AttributeQuery</code>
110      * @param dest <code>String</code>
111      * @param issueInstant <code>DateTime</code>
112      * @param statement <code>AttributeStatement</code>
113      * @return <code>Response</code>
114      * @throws EncryptionException if an error occurs attempting to encrypt data
115      */
116     private Response buildResponse(org.opensaml.saml1.core.AttributeQuery message, String dest, DateTime issueInstant,
117             AttributeStatement statement) throws EncryptionException {
118         SAMLObjectBuilder<Response> responseBuilder = (SAMLObjectBuilder<Response>) getBuilderFactory().getBuilder(
119                 Response.DEFAULT_ELEMENT_NAME);
120         /*
121          * required: samlp:Status, ID, Version, IssueInstant
122          */
123         Response response = responseBuilder.buildObject();
124         response.setVersion(SAML_VERSION);
125         response.setID(getIdGenerator().generateIdentifier());
126         response.setInResponseTo(getDecoder().getSecurityPolicy().getIssuer().toString());
127         response.setIssueInstant(issueInstant);
128         response.setRecipient(dest);
129
130         response.setStatus(buildStatus());
131         response.getAssertions().add(buildAssertion(message.getSubject(), issueInstant, statement));
132         return response;
133     }
134
135     /**
136      * This builds the status response for this SAML request.
137      * 
138      * @return <code>Status</code>
139      */
140     private Status buildStatus() {
141         // build status
142         SAMLObjectBuilder<Status> statusBuilder = (SAMLObjectBuilder<Status>) getBuilderFactory().getBuilder(
143                 Status.DEFAULT_ELEMENT_NAME);
144         Status status = statusBuilder.buildObject();
145
146         // build status code
147         SAMLObjectBuilder<StatusCode> statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory()
148                 .getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
149         StatusCode statusCode = statusCodeBuilder.buildObject();
150         statusCode.setValue("Success");
151         status.setStatusCode(statusCode);
152         return status;
153     }
154
155     /**
156      * This builds the assertion for this SAML request.
157      * 
158      * @param messageSubject <code>Subject</code>
159      * @param issueInstant <code>DateTime</code>
160      * @param statement <code>AttributeStatement</code> of attributes
161      * @return <code>Assertion</code>
162      * @throws EncryptionException if an error occurs attempting to encrypt data
163      */
164     private Assertion buildAssertion(Subject messageSubject, DateTime issueInstant, AttributeStatement statement)
165             throws EncryptionException {
166         // build assertion
167         SAMLObjectBuilder<Assertion> assertionBuilder = (SAMLObjectBuilder<Assertion>) getBuilderFactory().getBuilder(
168                 Assertion.DEFAULT_ELEMENT_NAME);
169         /*
170          * required: saml:Issuer, ID, Version, IssueInstant
171          */
172         Assertion assertion = assertionBuilder.buildObject();
173         assertion.setID(getIdGenerator().generateIdentifier());
174         assertion.setIssueInstant(issueInstant);
175         assertion.setVersion(SAML_VERSION);
176         assertion.setIssuer(getRelyingPartyConfiguration().getProviderID());
177
178         // build subject
179         assertion.getSubjectStatements().add(buildSubjectStatement(messageSubject));
180         // build conditions
181         assertion.setConditions(buildConditions(issueInstant));
182         // build advice
183         assertion.setAdvice(buildAdvice());
184         // add attribute statement
185         assertion.getAttributeStatements().add(statement);
186         return assertion;
187     }
188
189     /**
190      * This builds the subject statement for this SAML request.
191      * 
192      * @param messageSubject <code>Subject</code>
193      * @return <code>SubjectStatement</code>
194      */
195     private SubjectStatement buildSubjectStatement(Subject messageSubject) {
196         // build subject
197         SAMLObjectBuilder<SubjectStatement> subjectStatementBuilder = (SAMLObjectBuilder<SubjectStatement>) getBuilderFactory()
198                 .getBuilder(SubjectStatement.DEFAULT_ELEMENT_NAME);
199         SubjectStatement subjectStatement = subjectStatementBuilder.buildObject();
200         subjectStatement.setSubject(messageSubject);
201         return subjectStatement;
202     }
203
204     /**
205      * This builds the conditions for this SAML request.
206      * 
207      * @param issueInstant <code>DateTime</code>
208      * @return <code>Conditions</code>
209      */
210     private Conditions buildConditions(DateTime issueInstant) {
211         SAMLObjectBuilder<Conditions> conditionsBuilder = (SAMLObjectBuilder<Conditions>) getBuilderFactory()
212                 .getBuilder(Conditions.DEFAULT_ELEMENT_NAME);
213         Conditions conditions = conditionsBuilder.buildObject();
214         conditions.setNotBefore(issueInstant);
215         // TODO conditions.setNotOnOrAfter();
216         // TODO add additional conditions : conditions.getConditions().add(Condition);
217         // TODO what about AudienceRestriction, OneTimeUse, ProxyRestriction?
218         return conditions;
219     }
220
221     /**
222      * This builds the advice for this SAML request.
223      * 
224      * @return <code>Advice</code>
225      */
226     private Advice buildAdvice() {
227         SAMLObjectBuilder<Advice> adviceBuilder = (SAMLObjectBuilder<Advice>) getBuilderFactory().getBuilder(
228                 Advice.DEFAULT_ELEMENT_NAME);
229         Advice advice = adviceBuilder.buildObject();
230         // advice.getAssertionIDReferences().add();
231         // advice.getAssertionURIReferences().add();
232         // advice.getAssertions().add();
233         // advice.getEncryptedAssertions().add();
234         // advice.addNamespace(namespace);
235         return advice;
236     }
237 }