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