001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001-2007 Janne Jalkanen (Janne.Jalkanen@iki.fi)
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package com.ecyrd.jspwiki.auth.login;
021:
022: import java.io.IOException;
023: import java.security.Principal;
024: import java.util.HashSet;
025: import java.util.Set;
026:
027: import javax.security.auth.callback.Callback;
028: import javax.security.auth.callback.UnsupportedCallbackException;
029: import javax.security.auth.login.FailedLoginException;
030: import javax.security.auth.login.LoginException;
031: import javax.servlet.http.HttpServletRequest;
032: import javax.servlet.http.HttpSession;
033:
034: import org.apache.log4j.Logger;
035:
036: import com.ecyrd.jspwiki.auth.Authorizer;
037: import com.ecyrd.jspwiki.auth.WikiPrincipal;
038: import com.ecyrd.jspwiki.auth.authorize.Role;
039: import com.ecyrd.jspwiki.auth.authorize.WebAuthorizer;
040:
041: /**
042: * <p>
043: * Logs in a user by extracting authentication data from an Http servlet
044: * session. First, the module tries to extract a Principal object out of the
045: * request directly using the servlet requests's <code>getUserPrincipal()</code>
046: * method. If one is found, authentication succeeds. If there is no
047: * Principal in the request, try calling <code>getRemoteUser()</code>. If
048: * the <code>remoteUser</code> exists but the UserDatabase can't find a matching
049: * profile, a generic WikiPrincipal is created with this value. If neither
050: * <code>userPrincipal</code> nor <code>remoteUser</code> exist in the request, the login fails.
051: * </p>
052: * <p>
053: * This module must be used with a CallbackHandler that supports the following
054: * Callback types:
055: * </p>
056: * <ol>
057: * <li>{@link HttpRequestCallback} - supplies the Http request object, from
058: * which the getRemoteUser and getUserPrincipal are extracted</li>
059: * <li>{@link UserDatabaseCallback} - supplies the user database for looking up
060: * the value of getRemoteUser</li>
061: * </ol>
062: * <p>
063: * After authentication, the Subject will contain principals
064: * {@link com.ecyrd.jspwiki.auth.authorize.Role#ALL}
065: * and {@link com.ecyrd.jspwiki.auth.authorize.Role#AUTHENTICATED},
066: * plus the Principal that represents the logged-in user.</p>
067: *
068: * @author Andrew Jaquith
069: * @since 2.3
070: */
071: public class WebContainerLoginModule extends AbstractLoginModule {
072:
073: protected static final Logger log = Logger
074: .getLogger(WebContainerLoginModule.class);
075:
076: /**
077: * Logs in the user.
078: * @see javax.security.auth.spi.LoginModule#login()
079: */
080: public boolean login() throws LoginException {
081: HttpRequestCallback rcb = new HttpRequestCallback();
082: AuthorizerCallback acb = new AuthorizerCallback();
083: Callback[] callbacks = new Callback[] { rcb, acb };
084: String userId = null;
085:
086: try {
087: // First, try to extract a Principal object out of the request
088: // directly. If we find one, we're done.
089: m_handler.handle(callbacks);
090: HttpServletRequest request = rcb.getRequest();
091: if (request == null) {
092: throw new LoginException("No Http request supplied.");
093: }
094: HttpSession session = request.getSession(false);
095: String sid = (session == null) ? NULL : session.getId();
096: Principal principal = request.getUserPrincipal();
097: if (principal == null) {
098: // If no Principal in request, try the remoteUser
099: if (log.isDebugEnabled()) {
100: log.debug("No userPrincipal found for session ID="
101: + sid);
102: }
103: userId = request.getRemoteUser();
104: if (userId == null) {
105: if (log.isDebugEnabled()) {
106: log.debug("No remoteUser found for session ID="
107: + sid);
108: }
109: throw new FailedLoginException(
110: "No remote user found");
111: }
112: principal = new WikiPrincipal(userId,
113: WikiPrincipal.LOGIN_NAME);
114: }
115: if (log.isDebugEnabled()) {
116: log.debug("Added Principal " + principal.getName()
117: + ",Role.ANONYMOUS,Role.ALL");
118: }
119: m_principals.add(new PrincipalWrapper(principal));
120:
121: // Add any container roles
122: injectWebAuthorizerRoles(acb.getAuthorizer(), request);
123:
124: // If login succeeds, commit these roles
125: m_principals.add(Role.AUTHENTICATED);
126: m_principals.add(Role.ALL);
127:
128: // If login succeeds, remove these principals/roles
129: m_principalsToOverwrite.add(WikiPrincipal.GUEST);
130: m_principalsToOverwrite.add(Role.ANONYMOUS);
131: m_principalsToOverwrite.add(Role.ASSERTED);
132:
133: // If login fails, remove these roles
134: m_principalsToRemove.add(Role.AUTHENTICATED);
135:
136: return true;
137: } catch (IOException e) {
138: log.error("IOException: " + e.getMessage());
139: return false;
140: } catch (UnsupportedCallbackException e) {
141: log
142: .error("UnsupportedCallbackException: "
143: + e.getMessage());
144: return false;
145: }
146: }
147:
148: /**
149: * If the current Authorizer is a
150: * {@link com.ecyrd.jwpwiki.auth.authorize.WebAuthorizer},
151: * this method iterates through each role returned by the
152: * authorizer (via
153: * {@link com.ecyrd.jwpwiki.auth.authorize.WebAuthorizer#isUserInRole( HttpServletRequest, Role)})
154: * and injects the appropriate ones into the Subject.
155: * @param acb the authorizer callback
156: * @param rcb the HTTP request
157: */
158: private final void injectWebAuthorizerRoles(Authorizer authorizer,
159: HttpServletRequest request) {
160: Principal[] roles = authorizer.getRoles();
161: Set foundRoles = new HashSet();
162: if (authorizer instanceof WebAuthorizer) {
163: WebAuthorizer wa = (WebAuthorizer) authorizer;
164: for (int i = 0; i < roles.length; i++) {
165: if (wa.isUserInRole(request, roles[i])) {
166: foundRoles.add(roles[i]);
167: if (log.isDebugEnabled()) {
168: log.debug("Added Principal "
169: + roles[i].getName() + ".");
170: }
171: }
172: }
173: }
174:
175: // Add these container roles if login succeeds
176: m_principals.addAll(foundRoles);
177:
178: // Make sure the same ones are removed if login fails
179: m_principalsToRemove.addAll(foundRoles);
180: }
181:
182: }
|