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 StringBuilder actionUrlBuilder = new StringBuilder();
124 if(!"".equals(request.getContextPath())){
125 actionUrlBuilder.append(request.getContextPath());
126 }
127 actionUrlBuilder.append(request.getServletPath());
128
129 request.setAttribute("actionUrl", actionUrlBuilder.toString());
130
131 try {
132 request.getRequestDispatcher(loginPage).forward(request, response);
133 log.debug("Redirecting to login page {}", loginPage);
134 } catch (IOException ex) {
135 log.error("Unable to redirect to login page.", ex);
136 } catch (ServletException ex) {
137 log.error("Unable to redirect to login page.", ex);
138 }
139 }
140
141
142
143
144
145
146
147
148
149
150
151 protected void authenticateUser(HttpServletRequest request, String username, String password) throws LoginException {
152 try {
153 log.debug("Attempting to authenticate user {}", username);
154
155 SimpleCallbackHandler cbh = new SimpleCallbackHandler(username, password);
156
157 javax.security.auth.login.LoginContext jaasLoginCtx = new javax.security.auth.login.LoginContext(
158 jaasConfigName, cbh);
159
160 jaasLoginCtx.login();
161 log.debug("Successfully authenticated user {}", username);
162
163 Subject loginSubject = jaasLoginCtx.getSubject();
164
165 Set<Principal> principals = loginSubject.getPrincipals();
166 principals.add(new UsernamePrincipal(username));
167
168 Set<Object> publicCredentials = loginSubject.getPublicCredentials();
169
170 Set<Object> privateCredentials = loginSubject.getPrivateCredentials();
171 privateCredentials.add(new UsernamePasswordCredential(username, password));
172
173 Subject userSubject = new Subject(false, principals, publicCredentials, privateCredentials);
174 request.setAttribute(LoginHandler.SUBJECT_KEY, userSubject);
175 } catch (LoginException e) {
176 log.debug("User authentication for " + username + " failed", e);
177 throw e;
178 } catch (Throwable e) {
179 log.debug("User authentication for " + username + " failed", e);
180 throw new LoginException("unknown authentication error");
181 }
182 }
183
184
185
186
187
188
189 protected class SimpleCallbackHandler implements CallbackHandler {
190
191
192 private String uname;
193
194
195 private String pass;
196
197
198
199
200
201
202
203 public SimpleCallbackHandler(String username, String password) {
204 uname = username;
205 pass = password;
206 }
207
208
209
210
211
212
213
214
215
216 public void handle(final Callback[] callbacks) throws UnsupportedCallbackException {
217
218 if (callbacks == null || callbacks.length == 0) {
219 return;
220 }
221
222 for (Callback cb : callbacks) {
223 if (cb instanceof NameCallback) {
224 NameCallback ncb = (NameCallback) cb;
225 ncb.setName(uname);
226 } else if (cb instanceof PasswordCallback) {
227 PasswordCallback pcb = (PasswordCallback) cb;
228 pcb.setPassword(pass.toCharArray());
229 }
230 }
231 }
232 }
233 }