001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 2004 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library 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 GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * Initial developer: Florent BENOIT
022: * --------------------------------------------------------------------------
023: * $Id: JAAS.java 4861 2004-06-01 13:27:09Z benoitf $
024: * --------------------------------------------------------------------------
025: */package org.objectweb.jonas.security.realm.web.jetty50;
026:
027: import java.security.Principal;
028: import java.security.acl.Group;
029: import java.security.cert.X509Certificate;
030: import java.util.ArrayList;
031: import java.util.Enumeration;
032: import java.util.Iterator;
033:
034: import javax.security.auth.Subject;
035: import javax.security.auth.login.AccountExpiredException;
036: import javax.security.auth.login.CredentialExpiredException;
037: import javax.security.auth.login.FailedLoginException;
038: import javax.security.auth.login.LoginContext;
039: import javax.security.auth.login.LoginException;
040:
041: import org.mortbay.http.HttpRequest;
042:
043: import org.objectweb.jonas.security.auth.callback.NoInputCallbackHandler;
044:
045: import org.objectweb.security.context.SecurityContext;
046: import org.objectweb.security.context.SecurityCurrent;
047:
048: import org.objectweb.util.monolog.api.BasicLevel;
049:
050: /**
051: * <p>
052: * Implementation of a JAAS Realm. (by a wrapper) It uses the entry
053: * JAAS_CONFIG_NAME from the JAAS config file
054: * @author Alexandre Thaveau (JAAS support with JOnAS)
055: * @author Marc-Antoine Bourgeot (JAAS support with JOnAS)
056: * @author Florent Benoit (Jetty 5.x)
057: */
058: public class JAAS extends Standard {
059:
060: /**
061: * Name used in the JAAS config file
062: */
063: private static final String JAAS_CONFIG_NAME = "jetty";
064:
065: /**
066: * Default Constructor
067: */
068: public JAAS() {
069: super ();
070: }
071:
072: /**
073: * Default Constructor
074: * @param name of the realm
075: */
076: public JAAS(String name) {
077: super ();
078: setName(name);
079: }
080:
081: /**
082: * Authenticate a user with a specific username and credentials
083: * @param username name of the user
084: * @param credentials credential of the user
085: * @param request httprequest
086: * @return a Jetty principal
087: */
088: public Principal authenticate(String username, Object credentials,
089: HttpRequest request) {
090:
091: // No authentication can be made with a null username
092: if (username == null) {
093: return null;
094: }
095:
096: Principal jettyPrincipal = (Principal) getUsers().get(username);
097: // User previously authenticated --> remove from the cache
098: if (jettyPrincipal != null) {
099: removeUser(username);
100: }
101:
102: NoInputCallbackHandler noInputCH = null;
103: LoginContext loginContext = null;
104: if (credentials instanceof X509Certificate[]) {
105: // Format the DN as a special username
106: String headerCertificate = "##DN##";
107: X509Certificate[] certs = (X509Certificate[]) credentials;
108:
109: username = certs[0].getSubjectDN().getName();
110: String usernameCert = headerCertificate.concat(username
111: .replace('=', '#').replace(',', '%').replace(' ',
112: '$'));
113: // Fill the callback handler for the login module with DN and
114: // certificate
115: noInputCH = new NoInputCallbackHandler(usernameCert, "",
116: certs[0]);
117: } else {
118: // Fill the callback handler for the login module with username and
119: // password
120: noInputCH = new NoInputCallbackHandler(username,
121: (String) credentials, null);
122: }
123:
124: //Establish a LoginContext to use for authentication
125: try {
126: loginContext = new LoginContext(JAAS_CONFIG_NAME, noInputCH);
127: } catch (LoginException e) {
128: getLogger()
129: .log(
130: BasicLevel.WARN,
131: "loginException : unable to create a LoginContext for : '"
132: + username + "'. Error : "
133: + e.getMessage());
134: return null;
135: }
136:
137: // Negotiate a login via this LoginContext
138: Subject subject = null;
139: try {
140: loginContext.login();
141: subject = loginContext.getSubject();
142: if (subject == null) {
143: getLogger().log(BasicLevel.ERROR,
144: "failedLogin for user :" + username);
145: return null;
146: }
147: } catch (AccountExpiredException e) {
148: if (getLogger().isLoggable(BasicLevel.ERROR)) {
149: getLogger().log(BasicLevel.ERROR,
150: "accountExpired for user :" + username);
151: }
152: return null;
153: } catch (CredentialExpiredException e) {
154: if (getLogger().isLoggable(BasicLevel.ERROR)) {
155: getLogger().log(BasicLevel.ERROR,
156: "credentialExpired for user :" + username);
157: }
158: return null;
159: } catch (FailedLoginException e) {
160: if (getLogger().isLoggable(BasicLevel.ERROR)) {
161: getLogger().log(BasicLevel.ERROR,
162: "failedLogin for user :" + username);
163: }
164: return null;
165: } catch (LoginException e) {
166: if (getLogger().isLoggable(BasicLevel.ERROR)) {
167: getLogger().log(BasicLevel.ERROR,
168: "loginException for user :" + username);
169: }
170: return null;
171: }
172:
173: // Get credentials iterators from the subject (first found)
174: //Iterator credentialsIterator =
175: // subject.getPrivateCredentials().iterator();
176: //String credential = (String) credentialsIterator.next();
177:
178: // Retrieve first principal name found (without groups)
179: Iterator iterator = subject.getPrincipals(Principal.class)
180: .iterator();
181: String userName = null;
182: while (iterator.hasNext() && (userName == null)) {
183: Principal principal = (Principal) iterator.next();
184: if (!(principal instanceof Group)) {
185: userName = principal.getName();
186: }
187: }
188:
189: // No name --> error
190: if (userName == null) {
191: getLogger().log(BasicLevel.ERROR,
192: "No Username found in the subject");
193: return null;
194: }
195:
196: // Retrieve all roles of the user (Roles are members of the Group class)
197: iterator = subject.getPrincipals(Group.class).iterator();
198: ArrayList roles = new ArrayList();
199: while (iterator.hasNext()) {
200: Group group = (Group) iterator.next();
201: Enumeration e = group.members();
202: while (e.hasMoreElements()) {
203: Principal p = (Principal) e.nextElement();
204: roles.add(p.getName());
205: }
206: }
207:
208: // Create a JettyPrincipal for Jetty
209: JettyPrincipal principal = new JettyPrincipal(userName, roles);
210:
211: // Register the subject in the security context
212: //SecurityContext ctx = new SecurityContext(subject);
213: SecurityContext ctx = new SecurityContext(userName, roles);
214: SecurityCurrent current = SecurityCurrent.getCurrent();
215: current.setSecurityContext(ctx);
216:
217: // Add to cache
218: addUser(username, principal);
219:
220: return principal;
221: }
222:
223: }
|