Remove logout method from Authn handler
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / idp / authn / provider / UsernamePasswordLoginServlet.java
1 /*
2  * Copyright [2006] [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.authn.provider;
18
19 import java.io.IOException;
20 import java.security.Principal;
21
22 import javax.security.auth.Subject;
23 import javax.security.auth.callback.Callback;
24 import javax.security.auth.callback.CallbackHandler;
25 import javax.security.auth.callback.NameCallback;
26 import javax.security.auth.callback.PasswordCallback;
27 import javax.security.auth.callback.UnsupportedCallbackException;
28 import javax.security.auth.login.LoginException;
29 import javax.servlet.http.HttpServlet;
30 import javax.servlet.http.HttpServletRequest;
31 import javax.servlet.http.HttpServletResponse;
32
33 import org.apache.log4j.Logger;
34 import org.opensaml.util.URLBuilder;
35 import org.opensaml.xml.util.DatatypeHelper;
36
37 import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationEngine;
38 import edu.internet2.middleware.shibboleth.idp.authn.LoginHandler;
39
40 /**
41  * This servlet should be protected by a filter which populates REMOTE_USER. The serlvet will then set the remote user
42  * field in a LoginContext.
43  */
44 public class UsernamePasswordLoginServlet extends HttpServlet {
45
46     /** Serial version UID. */
47     private static final long serialVersionUID = -572799841125956990L;
48
49     /** Class logger. */
50     private final Logger log = Logger.getLogger(RemoteUserAuthServlet.class);
51
52     /** Name of JAAS configuration used to authenticate users. */
53     private final String jaasConfigName = "ShibUserPassAuth";
54     
55     /** Login page name. */
56     private final String loginPage = "login.jsp";
57
58     /** HTTP request parameter containing the user name. */
59     private final String usernameAttribute = "j_username";
60
61     /** HTTP request parameter containing the user's password. */
62     private final String passwordAttribute = "j_password";
63
64     /** {@inheritDoc} */
65     public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
66         String username = DatatypeHelper.safeTrimOrNullString(request.getParameter(usernameAttribute));
67         String password = DatatypeHelper.safeTrimOrNullString(request.getParameter(passwordAttribute));
68
69         if(username == null || password == null){
70             redirectToLoginPage(request, response);
71             return;
72         }
73         
74         if(authenticateUser(request)){
75             AuthenticationEngine.returnToAuthenticationEngine(request, response);
76         }else{
77             redirectToLoginPage(request, response);
78             return;
79         }
80     }
81     
82     /**
83      * Sends the user to the login page.
84      * 
85      * @param request current request
86      * @param response current response
87      */
88     protected void redirectToLoginPage(HttpServletRequest request, HttpServletResponse response){
89         try {
90             StringBuilder pathBuilder = new StringBuilder();
91             pathBuilder.append(request.getContextPath());
92             pathBuilder.append("/");
93             pathBuilder.append(loginPage);
94
95             URLBuilder urlBuilder = new URLBuilder();
96             urlBuilder.setScheme(request.getScheme());
97             urlBuilder.setHost(request.getLocalName());
98             urlBuilder.setPort(request.getLocalPort());
99             urlBuilder.setPath(pathBuilder.toString());
100
101             if (log.isDebugEnabled()) {
102                 log.debug("Redirecting to login page " + urlBuilder.buildURL());
103             }
104
105             response.sendRedirect(urlBuilder.buildURL());
106             return;
107         } catch (IOException ex) {
108             log.error("Unable to redirect to login page.", ex);
109         }
110     }
111
112     /**
113      * Authenticate a username and password against JAAS.  If authentication succeeds the principal name and 
114      * subject are placed into the request in their respective attributes.
115      * 
116      * @param request current authentication request
117      * 
118      * @return true of authentication succeeds, false if not
119      */
120     protected boolean authenticateUser(HttpServletRequest request) {
121
122         try {
123             String username = DatatypeHelper.safeTrimOrNullString(request.getParameter(usernameAttribute));
124             String password = DatatypeHelper.safeTrimOrNullString(request.getParameter(passwordAttribute));
125
126             SimpleCallbackHandler cbh = new SimpleCallbackHandler(username, password);
127
128             javax.security.auth.login.LoginContext jaasLoginCtx = new javax.security.auth.login.LoginContext(
129                     jaasConfigName, cbh);
130
131             jaasLoginCtx.login();
132             log.debug("Successfully authenticated user " + username);
133             
134             Subject subject = jaasLoginCtx.getSubject();
135             Principal principal = subject.getPrincipals().iterator().next();
136             request.setAttribute(LoginHandler.PRINCIPAL_NAME_KEY, principal.getName());
137             request.setAttribute(LoginHandler.SUBJECT_KEY, jaasLoginCtx.getSubject());
138
139             return true;
140         } catch (LoginException e) {
141             if (log.isDebugEnabled()) {
142                 log.debug("User authentication failed", e);
143             }
144             return false;
145         }
146     }
147
148     /**
149      * A callback handler that provides static name and password data to a JAAS loging process.
150      * 
151      * This handler only supports {@link NameCallback} and {@link PasswordCallback}.
152      */
153     protected class SimpleCallbackHandler implements CallbackHandler {
154
155         /** Name of the user. */
156         private String uname;
157
158         /** User's password. */
159         private String pass;
160
161         /**
162          * Constructor.
163          * 
164          * @param username The username
165          * @param password The password
166          */
167         public SimpleCallbackHandler(String username, String password) {
168             uname = username;
169             pass = password;
170         }
171
172         /**
173          * Handle a callback.
174          * 
175          * @param callbacks The list of callbacks to process.
176          * 
177          * @throws UnsupportedCallbackException If callbacks has a callback other than {@link NameCallback} or
178          *             {@link PasswordCallback}.
179          */
180         public void handle(final Callback[] callbacks) throws UnsupportedCallbackException {
181
182             if (callbacks == null || callbacks.length == 0) {
183                 return;
184             }
185
186             for (Callback cb : callbacks) {
187                 if (cb instanceof NameCallback) {
188                     NameCallback ncb = (NameCallback) cb;
189                     ncb.setName(uname);
190                 } else if (cb instanceof PasswordCallback) {
191                     PasswordCallback pcb = (PasswordCallback) cb;
192                     pcb.setPassword(pass.toCharArray());
193                 }
194             }
195         }
196     }
197 }