Clean up unused variables reported by user.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / serviceprovider / AttributeRequestor.java
1 /*
2  * Copyright [2005] [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 /*
18  * AttributeRequestor.java
19  * 
20  * Generate a SAMLRequest to the AA for Attributes, then process the
21  * reply. In C++, this logic was InternalCCacheEntry::getNewResponse() 
22  * in shib-ccache.cpp.
23  * 
24  * The User Authentication was previously processed by ShibPOSTProfile
25  * and was stored by SessionManager in a Session object. Although the
26  * attributes might be fetched immediately, that is a strategy issue.
27  * In Java, we isolate the Attribute fetch in this separate module.
28  * 
29  * The Session block retains a copy of the original SAMLStatement from
30  * the POST, and it contains information about the remote Entity.
31  * However, the POST came from the HS (or IIDPProvider if you want to
32  * use SAML 2 terms), and this transaction has to go to the AA. So
33  * Metadata must be used to obtain the AttributeAuthorityRole and its
34  * associated Endpoint (URL).
35  * 
36  * The ApplicationInfo object for the configured Application presents
37  * a getAttributeDesignators method that can return a list of attributes
38  * to specify in the request. However, I can find no configuration element
39  * that corresponds to this, and no example logic. For now that method
40  * returns an empty collection and no particular attributes are requested.
41  * 
42  * The actual SSL session and exchange of data is performed by OpenSAML.
43  * Our interface to SAML is through the separate ShibBind module. The
44  * layers of processing and responsibilites need to be understood.
45  * 
46  * ShibBind uses the Metadata for the User's ID Providing Entity to
47  * locate the AttributeAuthorityRole and therefore the AA URL. This
48  * is passed to OpenSAML along with the request. Upon return, if any
49  * statements are signed it is the responsiblilty of ShibBind to call
50  * the Trust implementations to validate the signatures.
51  * 
52  * This module then checks, by calling the isSigned() property of
53  * SAMLObjects, to make sure that everything that is supposed to be
54  * signed actually was signed. ShibBind knows if a signature is valid,
55  * but this module knows if a signature was requred. This module also
56  * applies AAP to examine attributes and values and discard those that
57  * the policy doesn't accept.
58  * 
59  * Recovery Context: All exceptions handled and logged internally.
60  */
61 package edu.internet2.middleware.shibboleth.serviceprovider;
62
63 import java.util.Collection;
64 import java.util.Iterator;
65
66 import org.apache.log4j.Logger;
67 import org.opensaml.SAMLAssertion;
68 import org.opensaml.SAMLAttributeQuery;
69 import org.opensaml.SAMLAuthenticationStatement;
70 import org.opensaml.SAMLException;
71 import org.opensaml.SAMLRequest;
72 import org.opensaml.SAMLResponse;
73 import org.opensaml.SAMLSubject;
74 import org.opensaml.XML;
75
76 import edu.internet2.middleware.shibboleth.metadata.AttributeAuthorityDescriptor;
77 import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
78 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig.ApplicationInfo;
79
80 /**
81  * A static class with a static method. No objects are created
82  * 
83  * @author Howard Gilbert
84  */
85 public class AttributeRequestor {
86         
87         private static Logger log = Logger.getLogger(AttributeRequestor.class);
88         private static ServiceProviderContext context   = ServiceProviderContext.getInstance();
89         
90         private AttributeRequestor() {} // Prevent instantiation
91         
92         /**
93          * Request SAML Attribute response from AA
94          * 
95          * @param session Session object (from authentication POST)
96          * @return true if Attributes successfully stored in the Session
97          * @throws MetadataException If IdP has no configured AA
98          * @throws SAMLException If there is a problem with the reply
99          */
100         static 
101                         boolean    // return false if attributes are not fetched
102         fetchAttributes(
103                         Session session){
104                 
105             log.debug("Fetching attributes for session "+session.getKey()+
106                     " from "+session.getEntityId());
107             
108                 // Get local references to configuration objects
109                 ServiceProviderConfig config = context.getServiceProviderConfig();
110                 ApplicationInfo appinfo = config.getApplication(session.getApplicationId());
111                 
112                 // The Entity name was fed by by ShibPOSTProfile.accept(). Look it up now.
113                 EntityDescriptor entity = appinfo.lookup(session.getEntityId());
114                 if (entity==null) {
115                         log.error("Entity(Site) deleted from Metadata since authentication POST received: "+session.getEntityId());
116                         return false;
117                 }
118                 SAMLRequest request = null;
119                 
120                 AttributeAuthorityDescriptor aa = 
121                     entity.getAttributeAuthorityDescriptor(XML.SAML11_PROTOCOL_ENUM); // throws MetadataException
122                 if (aa==null) {
123                     log.error("No Attribute Authority in Metadata for ID="+entity.getId());
124                     return false;
125                 }
126                 
127                 // Build the Attribute Query 
128                 SAMLAttributeQuery query = null;
129                 SAMLSubject subject;
130                 try {
131                         SAMLAuthenticationStatement authenticationStatement = session.getAuthenticationStatement();
132                         if (authenticationStatement==null) {
133                             log.error("Session contains no Authentication Statement." );
134                             return false;
135                         }
136                         SAMLSubject subject2 = authenticationStatement.getSubject();
137                         if (subject2==null) {
138                             log.error("Session Authentication Statement contains no Subject." );
139                             return false;
140                         }
141                         subject = (SAMLSubject) subject2.clone();
142                 } catch (Exception e) {
143                     log.error("Unable to generate the query SAMLSubject from the Authenticaiton." );
144                     return false;
145                 }
146                 log.debug("Subject (Handle) is "+subject.getNameIdentifier());
147                 Collection attributeDesignators = appinfo.getAttributeDesignators();
148                 try {
149             query = 
150                 new SAMLAttributeQuery(
151                         subject,                 // Subject (i.e. Handle) from authentication
152                         appinfo.getProviderId(),  // SP Entity name
153                         attributeDesignators // Attributes to request, null for everything
154                         );
155
156             // Wrap the Query in a request
157             request = new SAMLRequest(query);
158         } catch (SAMLException e) {
159             log.error("AttributeRequestor unable to build SAML Query for Session "+session.getKey());
160             return false;
161         }
162                 
163                 
164                 // ShibBinding will extract URLs from the Metadata and build
165                 // parameters so SAML can create the session. It also interfaces
166                 // to Trust to verify that any signed objects have trusted signatures.
167                 SAMLResponse response = null;
168                 try {
169             ShibBinding binding = new ShibBinding(session.getApplicationId());
170                         response = binding.send(request,aa,null,null,appinfo);
171                 } catch (SAMLException e) {;} // response will be null
172                 if (response==null) {
173                         log.error("AttributeRequestor Query to remote AA returned no response from "+session.getEntityId());
174                         return false;
175                 }
176                 
177                 
178                 // Check each assertion in the response.
179         int acount = 0;
180                 Iterator assertions = response.getAssertions();
181                 while (assertions.hasNext()) {
182                         SAMLAssertion assertion = (SAMLAssertion) assertions.next();
183 //                      if (signedAssertions && !assertion.isSigned()) {
184 //                              log.warn("AttributeRequestor has removed unsigned assertion from response from "+session.getEntityId());
185 //                              response.removeAssertion(acount);
186 //                              continue;
187 //                      }
188                         
189             try {
190                 appinfo.applyAAP(assertion,aa); // apply each AAP to this assertion
191                 acount++;
192             }
193                         catch (SAMLException ex) {
194                 response.removeAssertion(acount); // AAP rejected all statements for this assertion
195             }
196                 }
197
198                 // A response may end up with no attributes, but that is not an error.
199                 // Maybe there is just nothing important to say about this user.
200                 
201                 session.setAttributeResponse(response); // Save response in Session object
202                 return true;
203         }
204
205 }