change session key to the right scope
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / idp / profile / saml2 / AuthenticationRequestBrowserPost.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.saml2;
18
19 import javax.servlet.ServletRequest;
20 import javax.servlet.ServletResponse;
21 import javax.servlet.http.HttpServletRequest;
22 import javax.servlet.http.HttpServletResponse;
23 import javax.servlet.http.HttpSession;
24
25 import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
26 import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
27 import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
28 import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
29 import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml2.SSOConfiguration;
30
31 import org.apache.log4j.Logger;
32 import org.joda.time.DateTime;
33 import org.opensaml.common.SAMLObject;
34 import org.opensaml.common.binding.BindingException;
35 import org.opensaml.common.binding.decoding.MessageDecoder;
36 import org.opensaml.saml2.core.AuthnRequest;
37 import org.opensaml.saml2.core.Issuer;
38 import org.opensaml.saml2.core.Response;
39 import org.opensaml.saml2.metadata.SPSSODescriptor;
40 import org.opensaml.saml2.metadata.provider.MetadataProvider;
41 import org.opensaml.saml2.metadata.provider.MetadataProviderException;
42 import org.opensaml.ws.security.SecurityPolicyException;
43
44 /**
45  * Browser POST binding for SAML 2 AuthenticationRequest.
46  */
47 public class AuthenticationRequestBrowserPost extends AbstractAuthenticationRequest {
48     
49     /** Class logger. */
50     private static final Logger log = Logger.getLogger(AuthenticationRequestBrowserPost.class);
51     
52     /** SAML 2 Profile ID. */
53     protected static final String PROFILE_ID = "urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser";
54     
55     /** SAML 2 Binding URI. */
56     protected static final String BINDING_URI = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";
57     
58     /** Constructor. */
59     public AuthenticationRequestBrowserPost() {
60         super();
61     }
62     
63     /** {@inheritDoc} */
64     public String getProfileId() {
65         return PROFILE_ID;
66     }
67     
68     /** {@inheritDoc} */
69     public void processRequest(final ProfileRequest<ServletRequest> request,
70             final ProfileResponse<ServletResponse> response)
71             throws ProfileException {
72         
73         // Only http servlets are supported for now.
74         if (!(request.getRawRequest() instanceof HttpServletRequest)) {
75             log.error("Received a non-HTTP request");
76             throw new ProfileException("Received a non-HTTP request");
77         }
78         
79         HttpServletRequest httpRequest = (HttpServletRequest) request.getRawRequest();
80         HttpServletResponse httpResponse = (HttpServletResponse) response.getRawResponse();
81         HttpSession httpSession = httpRequest.getSession();
82         
83         AuthnRequest authnRequest = null;
84         String issuer = null;
85         MetadataProvider metadataProvider = null;
86         RelyingPartyConfiguration relyingParty = null;
87         SSOConfiguration ssoConfig = null;
88         SPSSODescriptor spDescriptor = null;
89         
90         
91         // If the user hasn't been authenticated, validate the AuthnRequest
92         // and redirect to AuthenticationManager to authenticate the user.
93         if (!hasUserAuthenticated(httpSession)) {
94             
95             try {
96                 // decode the AuthnRequest
97                 MessageDecoder<ServletRequest> decoder = getMessageDecoderFactory().getMessageDecoder(BINDING_URI);
98                 if (decoder == null) {
99                     log.error("SAML 2 AuthnRequest: No MessageDecoder registered for " + BINDING_URI);
100                     throw new ProfileException("SAML 2 AuthnRequest: No MessageDecoder registered for " + BINDING_URI);
101                 }
102                 
103                 decoder.setMetadataProvider(getMetadataProvider());
104                 populateMessageDecoder(decoder);
105                 decoder.decode();
106                 
107                 SAMLObject samlObject = decoder.getSAMLMessage();
108                 if (!(samlObject instanceof AuthnRequest)) {
109                     log.error("SAML 2 AuthnRequest: Received message is not a SAML 2 Authentication Request");
110                     throw new ProfileException("SAML 2 AuthnRequest: Received message is not a SAML 2 Authentication Request");
111                 }
112                 
113                 authnRequest = (AuthnRequest) samlObject;
114                 issuer = decoder.getSecurityPolicy().getIssuer();
115                 
116                 // check that we have metadata for the RP
117                 metadataProvider = getRelyingPartyConfigurationManager().getMetadataProvider();
118                 relyingParty = getRelyingPartyConfigurationManager().getRelyingPartyConfiguration(issuer);
119                 ssoConfig = (SSOConfiguration) relyingParty.getProfileConfigurations().get(SSOConfiguration.PROFILE_ID);
120                 
121                 try {
122                     spDescriptor = metadataProvider.getEntityDescriptor(
123                             relyingParty.getRelyingPartyId()).getSPSSODescriptor(
124                             SAML20_PROTOCOL_URI);
125                 } catch (MetadataProviderException ex) {
126                     log.error(
127                             "SAML 2 Authentication Request: Unable to locate metadata for SP "
128                             + issuer + " for protocol " + SAML20_PROTOCOL_URI, ex);
129                     throw new ProfileException("SAML 2 Authentication Request: Unable to locate metadata for SP "
130                             + issuer + " for protocol " + SAML20_PROTOCOL_URI, ex);
131                 }
132                 
133                 if (spDescriptor == null) {
134                     log.error("SAML 2 Authentication Request: Unable to locate metadata for SP "
135                             + issuer + " for protocol " + SAML20_PROTOCOL_URI);
136                     throw new ProfileException("SAML 2 Authentication Request: Unable to locate metadata for SP "
137                             + issuer + " for protocol " + SAML20_PROTOCOL_URI);
138                 }
139                 
140                 verifyAuthnRequest(authnRequest, issuer, relyingParty, httpSession);
141                 storeRequestData(httpSession, authnRequest, issuer, relyingParty, ssoConfig, spDescriptor);
142                 authenticateUser(authnRequest, httpSession, httpRequest, httpResponse);
143                 
144             } catch (BindingException ex) {
145                 log.error("SAML 2 Authentication Request: Unable to decode SAML 2 Authentication Request", ex);
146                 throw new ProfileException(
147                         "SAML 2 Authentication Request: Unable to decode SAML 2 Authentication Request", ex);
148             } catch (SecurityPolicyException ex) {
149                log.error("SAML 2 Authentication Request: Security error while decoding SAML 2 Authentication Request", ex);
150             } catch (AuthenticationRequestException ex) {
151             
152                 // AuthN failed. Send the failure status.
153                 retrieveRequestData(httpSession, authnRequest, issuer, relyingParty, ssoConfig, spDescriptor);
154                 Response failureResponse = buildResponse(authnRequest.getID(), new DateTime(), issuer, ex.getStatus());
155                 encodeResponse(BINDING_URI, response, failureResponse, relyingParty, ssoConfig, spDescriptor);
156             } 
157         }
158         
159         // The user has already been authenticated,
160         // so generate an AuthenticationStatement.
161         retrieveRequestData(httpSession, authnRequest, issuer, relyingParty, ssoConfig, spDescriptor);
162         Response samlResponse = evaluateRequest(authnRequest, issuer, httpSession, relyingParty, ssoConfig, spDescriptor);
163         encodeResponse(BINDING_URI, response, samlResponse, relyingParty, ssoConfig, spDescriptor);
164     }
165 }