Wire in security policy appropriately
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / idp / profile / AbstractSAMLProfileHandler.java
1 /*
2  * Copyright [2007] [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;
18
19 import java.util.List;
20 import java.util.Map;
21
22 import javax.servlet.http.HttpServletRequest;
23
24 import org.apache.log4j.Logger;
25 import org.opensaml.common.IdentifierGenerator;
26 import org.opensaml.common.binding.decoding.SAMLMessageDecoder;
27 import org.opensaml.common.binding.encoding.SAMLMessageEncoder;
28 import org.opensaml.log.Level;
29 import org.opensaml.saml2.metadata.provider.MetadataProvider;
30 import org.opensaml.ws.message.encoder.MessageEncodingException;
31 import org.opensaml.ws.transport.InTransport;
32 import org.opensaml.ws.transport.http.HttpServletRequestAdapter;
33
34 import edu.internet2.middleware.shibboleth.common.log.AuditLogEntry;
35 import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
36 import edu.internet2.middleware.shibboleth.common.profile.provider.AbstractShibbolethProfileHandler;
37 import edu.internet2.middleware.shibboleth.common.profile.provider.BaseSAMLProfileRequestContext;
38 import edu.internet2.middleware.shibboleth.common.relyingparty.provider.SAMLMDRelyingPartyConfigurationManager;
39 import edu.internet2.middleware.shibboleth.idp.session.Session;
40
41 /**
42  * Base class for SAML profile handlers.
43  */
44 public abstract class AbstractSAMLProfileHandler extends
45         AbstractShibbolethProfileHandler<SAMLMDRelyingPartyConfigurationManager, Session> {
46
47     /** SAML message audit log. */
48     private final Logger auditLog = Logger.getLogger(AuditLogEntry.AUDIT_LOGGER_NAME);
49
50     /** Class logger. */
51     private final Logger log = Logger.getLogger(AbstractSAMLProfileHandler.class);
52
53     /** Generator of IDs which may be used for SAML assertions, requests, etc. */
54     private IdentifierGenerator idGenerator;
55
56     /** All the SAML message decoders configured for the IdP. */
57     private Map<String, SAMLMessageDecoder> messageDecoders;
58
59     /** All the SAML message encoders configured for the IdP. */
60     private Map<String, SAMLMessageEncoder> messageEncoders;
61
62     /** SAML message binding used by inbound messages. */
63     private String inboundBinding;
64
65     /** SAML message bindings that may be used by outbound messages. */
66     private List<String> supportedOutboundBindings;
67
68     /** Constructor. */
69     protected AbstractSAMLProfileHandler() {
70         super();
71     }
72
73     /**
74      * Gets the audit log for this handler.
75      * 
76      * @return audit log for this handler
77      */
78     protected Logger getAduitLog() {
79         return auditLog;
80     }
81
82     /**
83      * Gets an ID generator which may be used for SAML assertions, requests, etc.
84      * 
85      * @return ID generator
86      */
87     public IdentifierGenerator getIdGenerator() {
88         return idGenerator;
89     }
90
91     /**
92      * Gets the SAML message binding used by inbound messages.
93      * 
94      * @return SAML message binding used by inbound messages
95      */
96     public String getInboundBinding() {
97         return inboundBinding;
98     }
99
100     /**
101      * Gets all the SAML message decoders configured for the IdP indexed by SAML binding URI.
102      * 
103      * @return SAML message decoders configured for the IdP indexed by SAML binding URI
104      */
105     public Map<String, SAMLMessageDecoder> getMessageDecoders() {
106         return messageDecoders;
107     }
108
109     /**
110      * Gets all the SAML message encoders configured for the IdP indexed by SAML binding URI.
111      * 
112      * @return SAML message encoders configured for the IdP indexed by SAML binding URI
113      */
114     public Map<String, SAMLMessageEncoder> getMessageEncoders() {
115         return messageEncoders;
116     }
117
118     /**
119      * A convenience method for retrieving the SAML metadata provider from the relying party manager.
120      * 
121      * @return the metadata provider or null
122      */
123     public MetadataProvider getMetadataProvider() {
124         SAMLMDRelyingPartyConfigurationManager rpcManager = getRelyingPartyConfigurationManager();
125         if (rpcManager != null) {
126             return rpcManager.getMetadataProvider();
127         }
128
129         return null;
130     }
131
132     /**
133      * Gets the SAML message bindings that may be used by outbound messages.
134      * 
135      * @return SAML message bindings that may be used by outbound messages
136      */
137     public List<String> getSupportedOutboundBindings() {
138         return supportedOutboundBindings;
139     }
140
141     /**
142      * Gets the user's session, if there is one.
143      * 
144      * @param inTransport current inbound transport
145      * 
146      * @return user's session
147      */
148     protected Session getUserSession(InTransport inTransport) {
149         String sessionId = getUserSessionId(inTransport);
150         return getSessionManager().getSession(sessionId);
151     }
152
153     /**
154      * Gets the user's session ID from the current request.
155      * 
156      * @param inTransport current inbound transport
157      * 
158      * @return user's session ID
159      */
160     protected String getUserSessionId(InTransport inTransport) {
161         HttpServletRequest rawRequest = ((HttpServletRequestAdapter) inTransport).getWrappedRequest();
162
163         if (rawRequest != null) {
164             return (String) rawRequest.getSession().getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
165         }
166
167         return null;
168     }
169
170     /**
171      * Gets an ID generator which may be used for SAML assertions, requests, etc.
172      * 
173      * @param generator an ID generator which may be used for SAML assertions, requests, etc
174      */
175     public void setIdGenerator(IdentifierGenerator generator) {
176         idGenerator = generator;
177     }
178
179     /**
180      * Sets the SAML message binding used by inbound messages.
181      * 
182      * @param binding SAML message binding used by inbound messages
183      */
184     public void setInboundBinding(String binding) {
185         inboundBinding = binding;
186     }
187
188     /**
189      * Sets all the SAML message decoders configured for the IdP indexed by SAML binding URI.
190      * 
191      * @param decoders SAML message decoders configured for the IdP indexed by SAML binding URI
192      */
193     public void setMessageDecoders(Map<String, SAMLMessageDecoder> decoders) {
194         messageDecoders = decoders;
195     }
196
197     /**
198      * Sets all the SAML message encoders configured for the IdP indexed by SAML binding URI.
199      * 
200      * @param encoders SAML message encoders configured for the IdP indexed by SAML binding URI
201      */
202     public void setMessageEncoders(Map<String, SAMLMessageEncoder> encoders) {
203         messageEncoders = encoders;
204     }
205
206     /**
207      * Sets the SAML message bindings that may be used by outbound messages.
208      * 
209      * @param bindings SAML message bindings that may be used by outbound messages
210      */
211     public void setSupportedOutboundBindings(List<String> bindings) {
212         supportedOutboundBindings = bindings;
213     }
214
215     /**
216      * Encodes the request's SAML response and writes it to the servlet response.
217      * 
218      * @param requestContext current request context
219      * 
220      * @throws ProfileException thrown if no message encoder is registered for this profiles binding
221      */
222     protected void encodeResponse(BaseSAMLProfileRequestContext requestContext) throws ProfileException {
223         if (log.isDebugEnabled()) {
224             log.debug("Encoding response to SAML request " + requestContext.getInboundSAMLMessageId()
225                     + " from relying party " + requestContext.getPeerEntityId());
226         }
227
228         try {
229             SAMLMessageEncoder encoder = getMessageEncoders().get(requestContext.getPeerEntityEndpoint().getBinding());
230             if (encoder == null) {
231                 throw new ProfileException("No outbound message encoder configured for binding "
232                         + requestContext.getPeerEntityEndpoint().getBinding());
233             }
234             requestContext.setMessageEncoder(encoder);
235             encoder.encode(requestContext);
236         } catch (MessageEncodingException e) {
237             throw new ProfileException("Unable to encode response to relying party: "
238                     + requestContext.getPeerEntityId(), e);
239         }
240     }
241     
242     /**
243      * Writes an aduit log entry indicating the successful response to the attribute request.
244      * 
245      * @param context current request context
246      */
247     protected void writeAuditLogEntry(BaseSAMLProfileRequestContext context) {
248         AuditLogEntry auditLogEntry = new AuditLogEntry();
249         auditLogEntry.setMessageProfile(getProfileId());
250         auditLogEntry.setPrincipalAuthenticationMethod(context.getPrincipalAuthenticationMethod());
251         auditLogEntry.setPrincipalName(context.getPrincipalName());
252         auditLogEntry.setAssertingPartyId(context.getLocalEntityId());
253         auditLogEntry.setRelyingPartyId(context.getPeerEntityId());
254         auditLogEntry.setRequestBinding(context.getMessageDecoder().getBindingURI());
255         auditLogEntry.setRequestId(context.getInboundSAMLMessageId());
256         auditLogEntry.setResponseBinding(context.getMessageEncoder().getBindingURI());
257         auditLogEntry.setResponseId(context.getOutboundSAMLMessageId());
258         if (context.getReleasedAttributes() != null) {
259             auditLogEntry.getReleasedAttributes().addAll(context.getReleasedAttributes());
260         }
261         getAduitLog().log(Level.CRITICAL, auditLogEntry);
262     }
263 }