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