2 * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package edu.internet2.middleware.shibboleth.idp.profile;
19 import java.util.List;
22 import javax.servlet.http.HttpServletRequest;
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;
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;
43 * Base class for SAML profile handlers.
45 public abstract class AbstractSAMLProfileHandler extends
46 AbstractShibbolethProfileHandler<SAMLMDRelyingPartyConfigurationManager, Session> {
48 /** SAML message audit log. */
49 private final Logger auditLog = Logger.getLogger(AuditLogEntry.AUDIT_LOGGER_NAME);
52 private final Logger log = Logger.getLogger(AbstractSAMLProfileHandler.class);
54 /** Generator of IDs which may be used for SAML assertions, requests, etc. */
55 private IdentifierGenerator idGenerator;
57 /** All the SAML message decoders configured for the IdP. */
58 private Map<String, SAMLMessageDecoder> messageDecoders;
60 /** All the SAML message encoders configured for the IdP. */
61 private Map<String, SAMLMessageEncoder> messageEncoders;
63 /** SAML message binding used by inbound messages. */
64 private String inboundBinding;
66 /** SAML message bindings that may be used by outbound messages. */
67 private List<String> supportedOutboundBindings;
70 protected AbstractSAMLProfileHandler() {
75 * Gets the audit log for this handler.
77 * @return audit log for this handler
79 protected Logger getAduitLog() {
84 * Gets an ID generator which may be used for SAML assertions, requests, etc.
86 * @return ID generator
88 public IdentifierGenerator getIdGenerator() {
93 * Gets the SAML message binding used by inbound messages.
95 * @return SAML message binding used by inbound messages
97 public String getInboundBinding() {
98 return inboundBinding;
102 * Gets all the SAML message decoders configured for the IdP indexed by SAML binding URI.
104 * @return SAML message decoders configured for the IdP indexed by SAML binding URI
106 public Map<String, SAMLMessageDecoder> getMessageDecoders() {
107 return messageDecoders;
111 * Gets all the SAML message encoders configured for the IdP indexed by SAML binding URI.
113 * @return SAML message encoders configured for the IdP indexed by SAML binding URI
115 public Map<String, SAMLMessageEncoder> getMessageEncoders() {
116 return messageEncoders;
120 * A convenience method for retrieving the SAML metadata provider from the relying party manager.
122 * @return the metadata provider or null
124 public MetadataProvider getMetadataProvider() {
125 SAMLMDRelyingPartyConfigurationManager rpcManager = getRelyingPartyConfigurationManager();
126 if (rpcManager != null) {
127 return rpcManager.getMetadataProvider();
134 * Gets the SAML message bindings that may be used by outbound messages.
136 * @return SAML message bindings that may be used by outbound messages
138 public List<String> getSupportedOutboundBindings() {
139 return supportedOutboundBindings;
143 * Gets the user's session, if there is one.
145 * @param inTransport current inbound transport
147 * @return user's session
149 protected Session getUserSession(InTransport inTransport) {
150 String sessionId = getUserSessionId(inTransport);
151 return getSessionManager().getSession(sessionId);
155 * Gets the user's session ID from the current request.
157 * @param inTransport current inbound transport
159 * @return user's session ID
161 protected String getUserSessionId(InTransport inTransport) {
162 HttpServletRequest rawRequest = ((HttpServletRequestAdapter) inTransport).getWrappedRequest();
164 if (rawRequest != null) {
165 return (String) rawRequest.getSession().getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
172 * Gets an ID generator which may be used for SAML assertions, requests, etc.
174 * @param generator an ID generator which may be used for SAML assertions, requests, etc
176 public void setIdGenerator(IdentifierGenerator generator) {
177 idGenerator = generator;
181 * Sets the SAML message binding used by inbound messages.
183 * @param binding SAML message binding used by inbound messages
185 public void setInboundBinding(String binding) {
186 inboundBinding = binding;
190 * Sets all the SAML message decoders configured for the IdP indexed by SAML binding URI.
192 * @param decoders SAML message decoders configured for the IdP indexed by SAML binding URI
194 public void setMessageDecoders(Map<String, SAMLMessageDecoder> decoders) {
195 messageDecoders = decoders;
199 * Sets all the SAML message encoders configured for the IdP indexed by SAML binding URI.
201 * @param encoders SAML message encoders configured for the IdP indexed by SAML binding URI
203 public void setMessageEncoders(Map<String, SAMLMessageEncoder> encoders) {
204 messageEncoders = encoders;
208 * Sets the SAML message bindings that may be used by outbound messages.
210 * @param bindings SAML message bindings that may be used by outbound messages
212 public void setSupportedOutboundBindings(List<String> bindings) {
213 supportedOutboundBindings = bindings;
217 * Encodes the request's SAML response and writes it to the servlet response.
219 * @param requestContext current request context
221 * @throws ProfileException thrown if no message encoder is registered for this profiles binding
223 protected void encodeResponse(BaseSAMLProfileRequestContext requestContext) throws ProfileException {
225 Endpoint peerEndpoint = requestContext.getPeerEntityEndpoint();
226 if (peerEndpoint == null) {
227 log.error("No return endpoint available for relying party " + requestContext.getInboundMessageIssuer());
228 throw new ProfileException("No peer endpoint available to which to send SAML response");
231 SAMLMessageEncoder encoder = getMessageEncoders().get(requestContext.getPeerEntityEndpoint().getBinding());
232 if (encoder == null) {
233 log.error("No outbound message encoder configured for binding "
234 + requestContext.getPeerEntityEndpoint().getBinding());
235 throw new ProfileException("No outbound message encoder configured for binding "
236 + requestContext.getPeerEntityEndpoint().getBinding());
239 if (log.isDebugEnabled()) {
240 log.debug("Encoding response to SAML request " + requestContext.getInboundSAMLMessageId()
241 + " from relying party " + requestContext.getInboundMessageIssuer() + " with outbound binding "
242 + encoder.getBindingURI());
245 requestContext.setMessageEncoder(encoder);
246 encoder.encode(requestContext);
247 } catch (MessageEncodingException e) {
248 throw new ProfileException("Unable to encode response to relying party: "
249 + requestContext.getInboundMessageIssuer(), e);
254 * Writes an aduit log entry indicating the successful response to the attribute request.
256 * @param context current request context
258 protected void writeAuditLogEntry(BaseSAMLProfileRequestContext context) {
259 AuditLogEntry auditLogEntry = new AuditLogEntry();
260 auditLogEntry.setMessageProfile(getProfileId());
261 auditLogEntry.setPrincipalAuthenticationMethod(context.getPrincipalAuthenticationMethod());
262 auditLogEntry.setPrincipalName(context.getPrincipalName());
263 auditLogEntry.setAssertingPartyId(context.getLocalEntityId());
264 auditLogEntry.setRelyingPartyId(context.getInboundMessageIssuer());
265 auditLogEntry.setRequestBinding(context.getMessageDecoder().getBindingURI());
266 auditLogEntry.setRequestId(context.getInboundSAMLMessageId());
267 auditLogEntry.setResponseBinding(context.getMessageEncoder().getBindingURI());
268 auditLogEntry.setResponseId(context.getOutboundSAMLMessageId());
269 if (context.getReleasedAttributes() != null) {
270 auditLogEntry.getReleasedAttributes().addAll(context.getReleasedAttributes());
272 getAduitLog().log(Level.CRITICAL, auditLogEntry);