Organize logging into init, client service, and resource service threads
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / serviceprovider / AssertionConsumerServlet.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  * AuthenticatonAssertionConsumerServlet
19  * 
20  * The Shibboleth function previous known as the SHIRE.
21  * 
22  * Authentication Assertion Consumer is the SAML 2.0 term for what the
23  * SHIRE does. A SAML Assertion containing an Authentication statement
24  * with the "principal" identifier value equal to the handle vended by
25  * the Handle Server is received from the Browser. The Handle Server
26  * generated a form, prefilled it with a Bin64 encoding of the SAML
27  * statement, and included Javascript to automatically submit the form
28  * to this URL.
29  * 
30  * All HTTP, HTML, and servlet logic is localized to this layer of
31  * modules. Any information must be extracted from the Servlet API
32  * to be passed directly to Shibboleth.
33  * 
34  * The work is done by a ShibPOSTProfile object. It takes the Bin64
35  * encoded string, converts it to a SAMLObject, verifies structure,
36  * and validates signatures.
37  * 
38  * The resulting Authentication Assertion SAML statement is passed
39  * to Session Manager to create a new session. This process feeds
40  * back a session identifier that becomes the value of a Cookie sent
41  * back to the Browser to track the session.
42  * 
43  * If the decision is made to fetch attributes immediately, the 
44  * Session object can be passed to the static AttributeRequestor
45  * service. It generates a ShibBinding, sends a request to the AA,
46  * validates the response, applies AAP, and stores the resulting 
47  * SAML Attribute Assertion in the Session object.
48  */
49 package edu.internet2.middleware.shibboleth.serviceprovider;
50
51 import java.io.IOException;
52
53 import javax.servlet.ServletContext;
54 import javax.servlet.ServletException;
55 import javax.servlet.ServletOutputStream;
56 import javax.servlet.http.Cookie;
57 import javax.servlet.http.HttpServlet;
58 import javax.servlet.http.HttpServletRequest;
59 import javax.servlet.http.HttpServletResponse;
60
61 import org.apache.log4j.Logger;
62 import org.opensaml.SAMLBrowserProfile;
63 import org.opensaml.SAMLException;
64 import org.opensaml.SAMLResponse;
65 import org.opensaml.SAMLBrowserProfile.BrowserProfileResponse;
66 import org.w3c.dom.Element;
67
68 import x0.maceShibbolethTargetConfig1.SessionsDocument.Sessions;
69 import edu.internet2.middleware.shibboleth.common.Credentials;
70 import edu.internet2.middleware.shibboleth.common.ShibBrowserProfile;
71 import edu.internet2.middleware.shibboleth.metadata.MetadataException;
72 import edu.internet2.middleware.shibboleth.resource.AuthenticationFilter;
73 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig.ApplicationInfo;
74
75 /**
76  * AuthenticatonAssertionConsumerServlet
77  * 
78  * @author Howard Gilbert
79  */
80 public class AssertionConsumerServlet extends HttpServlet {
81
82         private static Logger log = Logger.getLogger(AssertionConsumerServlet.class.getName());
83         
84         private static ServiceProviderContext context = ServiceProviderContext.getInstance();
85         
86         private Element                 configuration = null;
87         private Credentials             credentials = null;
88         
89         public static final String SESSIONPARM =
90             "ShibbolethSessionId";
91         
92         
93         public void init() throws ServletException {
94                 super.init();
95                 ServletContext servletContext = this.getServletContext();
96                 
97                 // Note: the ServletContext should have been initialized by the Listener
98                 ServletContextInitializer.initServiceProvider(servletContext);
99                 
100                 // Establish linkage between the SP context and the RM Filter class
101                 AuthenticationFilter.setFilterSupport(new FilterSupportImpl());
102         }
103
104
105
106         /**
107          * Accept the SAML Assertion post from the HS.
108          * 
109          * @param request the request send by the client to the server
110          * @param response the response send by the server to the client
111          * @throws ServletException if an error occurred
112          * @throws IOException if an error occurred
113          */
114         public void doPost(
115                 HttpServletRequest request,
116                 HttpServletResponse response)
117                 // throws ServletException, IOException 
118                 {
119             ServletContextInitializer.beginService(request,response);
120                 try {
121             ServiceProviderConfig config = context.getServiceProviderConfig();
122             
123             String ipaddr = request.getRemoteAddr();
124             
125             // URL of Resource that triggered authorization
126             // I added support to the profile for extracting TARGET, but
127             // it's not too critical in Java since you can grab it easily anyway.
128             // Might be better in the 2.0 future though, since the bindings get trickier.
129             String target = request.getParameter("TARGET");
130             
131             // Map the Resource URL into an <Application>
132             String applicationId = config.mapRequest(target);
133             ApplicationInfo appinfo = config.getApplication(applicationId);
134             Sessions appSessionValues = appinfo.getApplicationConfig().getSessions();
135             String shireURL = request.getRequestURL().toString();
136             String providerId = appinfo.getApplicationConfig().getProviderId();
137             
138            
139             if (appSessionValues.getShireSSL()&& // Requires SSL
140                         !request.isSecure()) {       // isn't SSL
141                 log.error("Authentication Assersion not posted over SSL.");
142                 try {
143                     response.sendRedirect("/shibboleth/shireError.html");
144                 } catch (IOException e1) {
145                 }
146                 return;
147             }
148             
149             log.debug("Authentication received from "+ipaddr+" for "+target+
150                         "(application:"+applicationId+") (Provider:"+providerId+")");
151
152             String sessionId = createSessionFromPost(ipaddr, request, applicationId, shireURL, providerId, null);
153             
154             Cookie cookie = new Cookie("ShibbolethSPSession",sessionId);
155             response.addCookie(cookie);
156             
157             try {
158                                 if (target.equals("SendAttributesBackToMe")) {
159                                         ServletOutputStream outputStream = response.getOutputStream();
160                                         response.setContentType("text/xml");
161                                         Session session = context.getSessionManager().findSession(sessionId,applicationId);
162                                         SAMLResponse attributeResponse = session.getAttributeResponse();
163                                         outputStream.print(attributeResponse.toString());
164                                 } else {
165                                         response.sendRedirect(target+"?"+SESSIONPARM+"="+sessionId);
166                                 }
167             }
168             catch (IOException e) {
169             }
170         }
171         catch (MetadataException e) {
172             log.error("Authentication Assertion source not found in Metadata.");
173             try {
174                 response.sendRedirect("/shibboleth/shireError.html");
175             }
176             catch (IOException e1) {
177             }
178         }
179         catch (SAMLException e) {
180             log.error("Authentication Assertion had invalid format.");
181             try {
182                 response.sendRedirect("/shibboleth/shireError.html");
183             }
184             catch (IOException e1) {
185             }
186         }
187         finally {
188             ServletContextInitializer.finishService(request,response);
189         }
190         }
191         
192     /**
193      * Create a Session object from SHIRE POST data
194      * 
195      * @param ipaddr IP Address of Browser
196      * @param bin64Assertion Authentication assertion from POST
197      * @param applicationId from RequestMap
198      * @param shireURL 
199      * @param providerId Our Entity name
200      * @return random key of Session
201      * @throws SAMLException
202      */
203     public static 
204     String createSessionFromPost(
205             String ipaddr, 
206             HttpServletRequest req, 
207             String applicationId, 
208             String shireURL, 
209             String providerId,
210             String emptySessionId
211             ) 
212     throws SAMLException {
213         String sessionid=null;
214         StringBuffer pproviderId = // Get back IdP Entity name from SAML
215             new StringBuffer();
216         String[] audiences = new String[1];
217         audiences[0]=providerId;
218         
219         ShibBrowserProfile profile = new ShibBrowserProfile(applicationId);
220         BrowserProfileResponse samldata = profile.receive(
221                 pproviderId,
222                 req,
223                 shireURL,   // My URL (Why??) To prevent attackers from redirecting messages. 
224                 SAMLBrowserProfile.PROFILE_POST,    // TODO: support both profiles 
225                 context.getReplayCache(),
226                 null,
227                 1
228         );
229         
230         // TODO: Audience/condition checking is now the profile caller's job.
231         
232         // The Authentication Assertion gets placed in a newly created
233         // Session object. Later, someone will get an Attribute Assertion
234         // and add it to the Session. The SessionID key is returned to
235         // the Browser as a Cookie.
236         SessionManager sessionManager = context.getSessionManager();
237         sessionid = sessionManager.newSession(
238                 applicationId, 
239                 ipaddr, 
240                 pproviderId.toString(), 
241                 samldata.assertion, 
242                 samldata.authnStatement,
243                 emptySessionId);
244         
245         // Very agressive attribute fetch rule 
246         // Get the Attributes immediately! [good for debugging]
247         Session session = sessionManager.findSession(sessionid, applicationId);
248         AttributeRequestor.fetchAttributes(session);
249
250         return sessionid;
251     }
252
253
254
255     protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1)
256         throws ServletException, IOException {
257         // Currently the Assertion Consumer does not receive a GET
258     }
259         
260
261 }