1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package edu.internet2.middleware.shibboleth.idp.authn.provider;
18
19 import java.io.IOException;
20 import java.security.Principal;
21 import java.util.Set;
22
23 import javax.security.auth.Subject;
24 import javax.security.auth.callback.Callback;
25 import javax.security.auth.callback.CallbackHandler;
26 import javax.security.auth.callback.NameCallback;
27 import javax.security.auth.callback.PasswordCallback;
28 import javax.security.auth.callback.UnsupportedCallbackException;
29 import javax.security.auth.login.LoginException;
30 import javax.servlet.ServletConfig;
31 import javax.servlet.ServletException;
32 import javax.servlet.http.HttpServlet;
33 import javax.servlet.http.HttpServletRequest;
34 import javax.servlet.http.HttpServletResponse;
35
36 import org.opensaml.xml.util.DatatypeHelper;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationEngine;
41 import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationException;
42 import edu.internet2.middleware.shibboleth.idp.authn.LoginHandler;
43 import edu.internet2.middleware.shibboleth.idp.authn.UsernamePrincipal;
44
45
46
47
48
49 public class UsernamePasswordLoginServlet extends HttpServlet {
50
51
52 private static final long serialVersionUID = -572799841125956990L;
53
54
55 private final Logger log = LoggerFactory.getLogger(UsernamePasswordLoginServlet.class);
56
57
58 private String jaasConfigName = "ShibUserPassAuth";
59
60
61 private final String jaasInitParam = "jaasConfigName";
62
63
64 private String loginPage = "login.jsp";
65
66
67 private final String loginPageInitParam = "loginPage";
68
69
70 private final String failureParam = "loginFailed";
71
72
73 private final String usernameAttribute = "j_username";
74
75
76 private final String passwordAttribute = "j_password";
77
78
79 public void init(ServletConfig config) throws ServletException {
80 super.init(config);
81
82 if (getInitParameter(jaasInitParam) != null) {
83 jaasConfigName = getInitParameter(jaasInitParam);
84 }
85
86 if (getInitParameter(loginPageInitParam) != null) {
87 loginPage = getInitParameter(loginPageInitParam);
88 }
89 if (!loginPage.startsWith("/")) {
90 loginPage = "/" + loginPage;
91 }
92 }
93
94
95 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException,
96 IOException {
97 String username = request.getParameter(usernameAttribute);
98 String password = request.getParameter(passwordAttribute);
99
100 if (username == null || password == null) {
101 redirectToLoginPage(request, response);
102 return;
103 }
104
105 try {
106 authenticateUser(request, username, password);
107 AuthenticationEngine.returnToAuthenticationEngine(request, response);
108 } catch (LoginException e) {
109 request.setAttribute(failureParam, "true");
110 request.setAttribute(LoginHandler.AUTHENTICATION_EXCEPTION_KEY, new AuthenticationException(e));
111 redirectToLoginPage(request, response);
112 }
113 }
114
115
116
117
118
119
120
121 protected void redirectToLoginPage(HttpServletRequest request, HttpServletResponse response) {
122
123 String requestContext = DatatypeHelper.safeTrimOrNullString(request.getContextPath());
124 if (requestContext == null) {
125 requestContext = "/";
126 }
127 request.setAttribute("actionUrl", requestContext + request.getServletPath());
128
129 try {
130 request.getRequestDispatcher(loginPage).forward(request, response);
131 log.debug("Redirecting to login page {}", loginPage);
132 } catch (IOException ex) {
133 log.error("Unable to redirect to login page.", ex);
134 } catch (ServletException ex) {
135 log.error("Unable to redirect to login page.", ex);
136 }
137 }
138
139
140
141
142
143
144
145
146
147
148
149 protected void authenticateUser(HttpServletRequest request, String username, String password) throws LoginException {
150 try {
151 log.debug("Attempting to authenticate user {}", username);
152
153 SimpleCallbackHandler cbh = new SimpleCallbackHandler(username, password);
154
155 javax.security.auth.login.LoginContext jaasLoginCtx = new javax.security.auth.login.LoginContext(
156 jaasConfigName, cbh);
157
158 jaasLoginCtx.login();
159 log.debug("Successfully authenticated user {}", username);
160
161 Subject loginSubject = jaasLoginCtx.getSubject();
162
163 Set<Principal> principals = loginSubject.getPrincipals();
164 principals.add(new UsernamePrincipal(username));
165
166 Set<Object> publicCredentials = loginSubject.getPublicCredentials();
167
168 Set<Object> privateCredentials = loginSubject.getPrivateCredentials();
169 privateCredentials.add(new UsernamePasswordCredential(username, password));
170
171 Subject userSubject = new Subject(false, principals, publicCredentials, privateCredentials);
172 request.setAttribute(LoginHandler.SUBJECT_KEY, userSubject);
173 } catch (LoginException e) {
174 log.debug("User authentication for " + username + " failed", e);
175 throw e;
176 } catch (Throwable e) {
177 log.debug("User authentication for " + username + " failed", e);
178 throw new LoginException("unknown authentication error");
179 }
180 }
181
182
183
184
185
186
187 protected class SimpleCallbackHandler implements CallbackHandler {
188
189
190 private String uname;
191
192
193 private String pass;
194
195
196
197
198
199
200
201 public SimpleCallbackHandler(String username, String password) {
202 uname = username;
203 pass = password;
204 }
205
206
207
208
209
210
211
212
213
214 public void handle(final Callback[] callbacks) throws UnsupportedCallbackException {
215
216 if (callbacks == null || callbacks.length == 0) {
217 return;
218 }
219
220 for (Callback cb : callbacks) {
221 if (cb instanceof NameCallback) {
222 NameCallback ncb = (NameCallback) cb;
223 ncb.setName(uname);
224 } else if (cb instanceof PasswordCallback) {
225 PasswordCallback pcb = (PasswordCallback) cb;
226 pcb.setPassword(pass.toCharArray());
227 }
228 }
229 }
230 }
231 }