View | Details | Raw Unified | Return to bug 28631
Collapse All | Expand All

(-)JAASRealm.java.old (-63 / +168 lines)
Lines 13-20 Link Here
13
 * See the License for the specific language governing permissions and
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
14
 * limitations under the License.
15
 */
15
 */
16
16
 
17
18
package org.apache.catalina.realm;
17
package org.apache.catalina.realm;
19
18
20
19
Lines 22-28 Link Here
22
import java.security.acl.Group;
21
import java.security.acl.Group;
23
import java.util.ArrayList;
22
import java.util.ArrayList;
24
import java.util.Enumeration;
23
import java.util.Enumeration;
24
import java.util.HashMap;
25
import java.util.Iterator;
25
import java.util.Iterator;
26
import java.util.List;
27
import java.util.Map;
26
28
27
import javax.security.auth.Subject;
29
import javax.security.auth.Subject;
28
import javax.security.auth.login.AccountExpiredException;
30
import javax.security.auth.login.AccountExpiredException;
Lines 62-68 Link Here
62
 * this Realm:</p>
64
 * this Realm:</p>
63
 * <ul>
65
 * <ul>
64
 * <li>The JAAS <code>LoginModule</code> is assumed to return a
66
 * <li>The JAAS <code>LoginModule</code> is assumed to return a
65
 *     <code>Subject with at least one <code>Principal</code> instance
67
 *     <code>Subject</code> with at least one <code>Principal</code> instance
66
 *     representing the user himself or herself, and zero or more separate
68
 *     representing the user himself or herself, and zero or more separate
67
 *     <code>Principals</code> representing the security roles authorized
69
 *     <code>Principals</code> representing the security roles authorized
68
 *     for this user.</li>
70
 *     for this user.</li>
Lines 87-95 Link Here
87
 * <li>It is a configuration error for the JAAS login method to return a
89
 * <li>It is a configuration error for the JAAS login method to return a
88
 *     validated <code>Subject</code> without a <code>Principal</code> that
90
 *     validated <code>Subject</code> without a <code>Principal</code> that
89
 *     matches the "user classes" list.</li>
91
 *     matches the "user classes" list.</li>
92
 * <li>By default, the enclosing Container's name serves as the
93
 *     application name used to obtain the JAAS LoginContext ("Catalina" in
94
 *     a default installation). Tomcat must be able to find an application
95
 *     with this name in the JAAS configuration file. Here is a hypothetical
96
 *     configuration file entry for a database-oriented login module that uses 
97
 *     a Tomcat-managed JNDI database resource:
98
 *     <blockquote><pre>Catalina {
99
	org.foobar.auth.DatabaseLoginModule REQUIRED
100
    JNDI_RESOURCE=jdbc/AuthDB
101
	  USER_TABLE=users
102
	  USER_ID_COLUMN=id
103
	  USER_NAME_COLUMN=name
104
	  USER_CREDENTIAL_COLUMN=password
105
	  ROLE_TABLE=roles
106
	  ROLE_NAME_COLUMN=name
107
	  PRINCIPAL_FACTORY=org.foobar.auth.impl.SimplePrincipalFactory;
108
};</pre></blockquote></li>
109
 * <li>To set the JAAS configuration file
110
 *     location, set the <code>CATALINA_OPTS</code> environment variable
111
 *     similar to the following:
112
<blockquote><code>CATALINA_OPTS="-Djava.security.auth.login.config=$CATALINA_HOME/conf/jaas.config"</code></blockquote>
113
 * </li>
114
 * <li>As part of the login process, JAASRealm registers its own <code>CallbackHandler</code>,
115
 *     called (unsurprisingly) <code>JAASCallbackHandler</code>. This handler supplies the 
116
 *     HTTP requests's username and credentials to the user-supplied <code>LoginModule</code></li>
117
 * <li>As with other <code>Realm</code> implementations, digested passwords are supported if
118
 *     the <code>&lt;Realm&gt;</code> element in <code>server.xml</code> contains a 
119
 *     <code>digest</code> attribute; <code>JAASCallbackHandler</code> will digest the password
120
 *     prior to passing it back to the <code>LoginModule</code></li>  
90
 * </ul>
121
 * </ul>
91
 *
122
 *
92
 * @author Craig R. McClanahan
123
 * @author Craig R. McClanahan
124
 * @author Andrew R. Jaquith
93
 * @version $Revision: 1.6 $ $Date: 2004/02/27 14:58:45 $
125
 * @version $Revision: 1.6 $ $Date: 2004/02/27 14:58:45 $
94
 */
126
 */
95
127
Lines 103-122 Link Here
103
135
104
    /**
136
    /**
105
     * The application name passed to the JAAS <code>LoginContext</code>,
137
     * The application name passed to the JAAS <code>LoginContext</code>,
106
     * which uses it to select the set of relevant <code>LoginModules</code>.
138
     * which uses it to select the set of relevant <code>LoginModule</code>s.
107
     */
139
     */
108
    protected String appName = null;
140
    protected String appName = null;
109
141
110
142
111
    /**
143
    /**
112
     * Descriptive information about this Realm implementation.
144
     * Descriptive information about this <code>Realm</code> implementation.
113
     */
145
     */
114
    protected static final String info =
146
    protected static final String info =
115
        "org.apache.catalina.realm.JAASRealm/1.0";
147
        "org.apache.catalina.realm.JAASRealm/1.0";
116
148
117
149
118
    /**
150
    /**
119
     * Descriptive information about this Realm implementation.
151
     * Descriptive information about this <code>Realm</code> implementation.
120
     */
152
     */
121
    protected static final String name = "JAASRealm";
153
    protected static final String name = "JAASRealm";
122
154
Lines 124-130 Link Here
124
    /**
156
    /**
125
     * The list of role class names, split out for easy processing.
157
     * The list of role class names, split out for easy processing.
126
     */
158
     */
127
    protected ArrayList roleClasses = new ArrayList();
159
    protected List roleClasses = new ArrayList();
128
160
129
161
130
    /**
162
    /**
Lines 137-158 Link Here
137
    /**
169
    /**
138
     * The set of user class names, split out for easy processing.
170
     * The set of user class names, split out for easy processing.
139
     */
171
     */
140
    protected ArrayList userClasses = new ArrayList();
172
    protected List userClasses = new ArrayList();
173
174
    /**
175
     * Map associating each user <code>Principal</code> object
176
     * with an array of role <code>Principal</code>s. 
177
     * This Map is read when <code>hasRole</code> is called.
178
     */
179
    protected Map roleMap = new HashMap();
141
180
142
181
143
    // ------------------------------------------------------------- Properties
182
    // ------------------------------------------------------------- Properties
144
183
145
    
184
    
146
    /**
185
    /**
147
     * setter for the appName member variable
186
     * setter for the <code>appName</code> member variable
148
     * @deprecated JAAS should use the Engine ( domain ) name and webpp/host overrides
187
     * @deprecated JAAS should use the <code>Engine</code> (domain) name and webpp/host overrides
149
     */
188
     */
150
    public void setAppName(String name) {
189
    public void setAppName(String name) {
151
        appName = name;
190
        appName = name;
152
    }
191
    }
153
    
192
    
154
    /**
193
    /**
155
     * getter for the appName member variable
194
     * getter for the <code>appName</code> member variable
156
     */
195
     */
157
    public String getAppName() {
196
    public String getAppName() {
158
        return appName;
197
        return appName;
Lines 168-174 Link Here
168
    }
207
    }
169
208
170
    /**
209
    /**
171
     * Comma-delimited list of <code>javax.security.Principal</code> classes
210
     * Comma-delimited list of <code>java.security.Principal</code> classes
172
     * that represent security roles.
211
     * that represent security roles.
173
     */
212
     */
174
    protected String roleClassNames = null;
213
    protected String roleClassNames = null;
Lines 177-182 Link Here
177
        return (this.roleClassNames);
216
        return (this.roleClassNames);
178
    }
217
    }
179
218
219
    /**
220
     * Sets the list of comma-delimited classes that represent 
221
     * roles. The classes in the list must implement <code>java.security.Principal</code>.
222
     * When this accessor is called (for example, by a <code>Digester</code>
223
     * instance parsing the
224
     * configuration file), it will parse the class names and store the resulting
225
     * string(s) into the <code>ArrayList</code> field </code>roleClasses</code>.
226
     */
180
    public void setRoleClassNames(String roleClassNames) {
227
    public void setRoleClassNames(String roleClassNames) {
181
        this.roleClassNames = roleClassNames;
228
        this.roleClassNames = roleClassNames;
182
        roleClasses.clear();
229
        roleClasses.clear();
Lines 200-206 Link Here
200
247
201
248
202
    /**
249
    /**
203
     * Comma-delimited list of <code>javax.security.Principal</code> classes
250
     * Comma-delimited list of <code>java.security.Principal</code> classes
204
     * that represent individual users.
251
     * that represent individual users.
205
     */
252
     */
206
    protected String userClassNames = null;
253
    protected String userClassNames = null;
Lines 209-214 Link Here
209
        return (this.userClassNames);
256
        return (this.userClassNames);
210
    }
257
    }
211
258
259
    /**
260
     * Sets the list of comma-delimited classes that represent individual
261
     * users. The classes in the list must implement <code>java.security.Principal</code>.
262
     * When this accessor is called (for example, by a <code>Digester</code>
263
     * instance parsing the
264
     * configuration file), it will parse the class names and store the resulting
265
     * string(s) into the <code>ArrayList</code> field </code>userClasses</code>.
266
     */
212
    public void setUserClassNames(String userClassNames) {
267
    public void setUserClassNames(String userClassNames) {
213
        this.userClassNames = userClassNames;
268
        this.userClassNames = userClassNames;
214
        userClasses.clear();
269
        userClasses.clear();
Lines 235-241 Link Here
235
290
236
291
237
    /**
292
    /**
238
     * Return the Principal associated with the specified username and
293
     * Return the <code>Principal</code> associated with the specified username and
239
     * credentials, if there is one; otherwise return <code>null</code>.
294
     * credentials, if there is one; otherwise return <code>null</code>.
240
     *
295
     *
241
     * If there are any errors with the JDBC connection, executing
296
     * If there are any errors with the JDBC connection, executing
Lines 243-249 Link Here
243
     * event is also logged, and the connection will be closed so that
298
     * event is also logged, and the connection will be closed so that
244
     * a subsequent request will automatically re-open it.
299
     * a subsequent request will automatically re-open it.
245
     *
300
     *
246
     * @param username Username of the Principal to look up
301
     * @param username Username of the <code>Principal</code> to look up
247
     * @param credentials Password or other credentials to use in
302
     * @param credentials Password or other credentials to use in
248
     *  authenticating this username
303
     *  authenticating this username
249
     */
304
     */
Lines 255-261 Link Here
255
        if( appName==null ) appName="Tomcat";
310
        if( appName==null ) appName="Tomcat";
256
311
257
        if( log.isDebugEnabled())
312
        if( log.isDebugEnabled())
258
            log.debug("Authenticating " + appName + " " +  username);
313
            log.debug(sm.getString("jaasRealm.beginLogin", username, appName));
259
314
260
        // What if the LoginModule is in the container class loader ?
315
        // What if the LoginModule is in the container class loader ?
261
        //
316
        //
Lines 273-279 Link Here
273
        }
328
        }
274
329
275
        if( log.isDebugEnabled())
330
        if( log.isDebugEnabled())
276
            log.debug("Login context created " + username);
331
            log.debug(sm.getString("jaasRealm.loginContextCreated", username));
277
332
278
        // Negotiate a login via this LoginContext
333
        // Negotiate a login via this LoginContext
279
        Subject subject = null;
334
        Subject subject = null;
Lines 306-321 Link Here
306
        }
361
        }
307
362
308
        if( log.isDebugEnabled())
363
        if( log.isDebugEnabled())
309
            log.debug("Getting principal " + subject);
364
            log.debug(sm.getString("jaasRealm.loginContextCreated", username));
310
365
311
        // Return the appropriate Principal for this authenticated Subject
366
        // Return the appropriate Principal for this authenticated Subject
312
        Principal principal = createPrincipal(username, subject);
367
        Principal principal = createPrincipal(username, subject);
313
        if (principal == null) {
368
        if (principal == null) {
314
            log.debug(sm.getString("jaasRealm.authenticateFailure", username));
369
            log.error(sm.getString("jaasRealm.authenticateFailure", username));
315
            return (null);
370
            return (null);
316
        }
371
        }
317
        if (log.isDebugEnabled()) {
372
        if (log.isDebugEnabled()) {
318
            log.debug(sm.getString("jaasRealm.authenticateSuccess", username));
373
            log.info(sm.getString("jaasRealm.authenticateSuccess", username, principal.getName()));
319
        }
374
        }
320
375
321
        return (principal);
376
        return (principal);
Lines 325-330 Link Here
325
        }
380
        }
326
    }
381
    }
327
382
383
    /**
384
     * Returns <code>true</code> if the specified user <code>Principal</code> has the specified
385
     * security role, within the context of this <code>Realm</code>; otherwise return
386
     * <code>false</code>. This will be true when 
387
     * an associated role <code>Principal</code> can be found whose <code>getName</code>
388
     * method returns a <code>String</code> equalling the specified role.
389
     * @param principal <code>Principal</code> for whom the role is to be checked
390
     * @param role Security role to be checked
391
     */
392
    public boolean hasRole(Principal principal, String role) {
393
394
        // Based on code from JAASRealm
395
        if (log.isDebugEnabled()) {
396
            log.debug(sm.getString("jaasRealm.isInRole.start", principal.getName(), role));
397
        }
398
        if ((principal == null) || (role == null) ||
399
          (roleMap.get(principal) == null)) {
400
            if (log.isDebugEnabled()) {
401
                log.debug(sm.getString("jaasRealm.isInRole.noPrincipalOrRole"));
402
            }
403
            return (false);
404
        }
405
        List roles = (List)roleMap.get(principal);
406
        if (log.isDebugEnabled()) {
407
            log.debug(sm.getString("jaasRealm.isInRole.principalCached", String.valueOf(roles.size())));
408
        }
409
        for (Iterator it = roles.iterator(); it.hasNext();) {
410
            Principal possessedRole = (Principal)it.next();
411
            String possessedRoleName = possessedRole.getName();
412
            if (log.isDebugEnabled()) {
413
                log.debug(sm.getString("jaasRealm.isInRole.possessesRole", possessedRole.getName()));
414
            }
415
            if (possessedRoleName.equals(role)) {
416
                if (log.isDebugEnabled()) {
417
                    log.debug(sm.getString("jaasRealm.isInRole.match"));
418
                }
419
                return (true);
420
            }
421
        }
422
        if (log.isDebugEnabled()) {
423
            log.error(sm.getString("jaasRealm.isInRole.noMatch"));
424
        }
425
        return (false);
426
    }
427
328
428
329
    // -------------------------------------------------------- Package Methods
429
    // -------------------------------------------------------- Package Methods
330
430
Lines 333-339 Link Here
333
433
334
434
335
    /**
435
    /**
336
     * Return a short name for this Realm implementation.
436
     * Return a short name for this <code>Realm</code> implementation.
337
     */
437
     */
338
    protected String getName() {
438
    protected String getName() {
339
439
Lines 353-359 Link Here
353
453
354
454
355
    /**
455
    /**
356
     * Return the Principal associated with the given user name.
456
     * Return the <code>Principal</code> associated with the given user name.
357
     */
457
     */
358
    protected Principal getPrincipal(String username) {
458
    protected Principal getPrincipal(String username) {
359
459
Lines 363-431 Link Here
363
463
364
464
365
    /**
465
    /**
366
     * Construct and return a <code>java.security.Principal</code> instance
466
     * Identify and return a <code>java.security.Principal</code> instance
367
     * representing the authenticated user for the specified Subject.  If no
467
     * representing the authenticated user for the specified <code>Subject</code>.
368
     * such Principal can be constructed, return <code>null</code>.
468
     * If no such Principal can be constructed, return <code>null</code>.
369
     *
469
     * @param subject The <code>Subject</code> representing the logged-in user
370
     * @param subject The Subject representing the logged in user
371
     */
470
     */
372
    protected Principal createPrincipal(String username, Subject subject) {
471
    protected Principal createPrincipal(String username, Subject subject) {
373
        // Prepare to scan the Principals for this Subject
472
        // Prepare to scan the Principals for this Subject
374
        String password = null; // Will not be carried forward
473
        String password = null; // Will not be carried forward
375
        ArrayList roles = new ArrayList();
474
        List roles = new ArrayList();
376
475
        Principal userPrincipal = null;
476
        
377
        // Scan the Principals for this Subject
477
        // Scan the Principals for this Subject
378
        Iterator principals = subject.getPrincipals().iterator();
478
        Iterator principals = subject.getPrincipals().iterator();
379
        while (principals.hasNext()) {
479
        while (principals.hasNext()) {
380
            Principal principal = (Principal) principals.next();
480
            Principal principal = (Principal) principals.next();
381
            // No need to look further - that's our own stuff
382
            if( principal instanceof GenericPrincipal ) {
383
                if( log.isDebugEnabled() )
384
                    log.debug("Found old GenericPrincipal " + principal );
385
                return principal;
386
            }
387
            String principalClass = principal.getClass().getName();
481
            String principalClass = principal.getClass().getName();
388
            if( log.isDebugEnabled() )
482
            if( log.isDebugEnabled() ) {
389
                log.info("Principal: " + principalClass + " " + principal);
483
                log.debug(sm.getString("jaasRealm.checkPrincipal", principal, principalClass));
390
391
            if (userClasses.contains(principalClass)) {
392
                // Override the default - which is the original user, accepted by
393
                // the friendly LoginManager
394
                username = principal.getName();
395
            }
484
            }
396
            if (roleClasses.contains(principalClass)) {
485
            if (userPrincipal == null && userClasses.contains(principalClass)) {
397
                roles.add(principal.getName());
486
                userPrincipal = principal;
487
                if( log.isDebugEnabled() ) {
488
                    log.debug(sm.getString("jaasRealm.userPrincipalSuccess", principal.getName()));
489
                }
398
            }
490
            }
399
            // Same as Jboss - that's a pretty clean solution
491
            if (roleClasses.contains(principalClass)) {
400
            if( (principal instanceof Group) &&
492
                roles.add(principal);
401
                 "Roles".equals( principal.getName())) {
493
                if( log.isDebugEnabled() ) {
402
                Group grp=(Group)principal;
494
                    log.debug(sm.getString("jaasRealm.rolePrincipalAdd", principal.getName()));
403
                Enumeration en=grp.members();
404
                while( en.hasMoreElements() ) {
405
                    Principal roleP=(Principal)en.nextElement();
406
                    roles.add( roleP.getName());
407
                }
495
                }
408
409
            }
496
            }
410
        }
497
        }
411
498
412
        // Create the resulting Principal for our authenticated user
499
        // Print failure message if needed
413
        if (username != null) {
500
        if (userPrincipal == null) {
414
            return (new GenericPrincipal(this, username, password, roles));
501
            if (log.isDebugEnabled()) {
415
        } else {
502
                log.debug(sm.getString("jaasRealm.userPrincipalFailure"));
416
            return (null);
503
                log.debug(sm.getString("jaasRealm.rolePrincipalFailure"));
504
            }
505
        }
506
        else {
507
            if (roles.size() == 0) {
508
                if (log.isDebugEnabled()) {
509
                    log.debug(sm.getString("jaasRealm.rolePrincipalFailure"));
510
                }
511
            }
512
            else {
513
                roleMap.put(userPrincipal, roles);
514
                if (log.isDebugEnabled()) {
515
                    log.debug(sm.getString("jaasRealm.rolePrincipalSuccess", String.valueOf(roles.size())));
516
                    log.debug(sm.getString("jaasRealm.cachePrincipal", userPrincipal.getName(), String.valueOf(roles.size())));
517
                }
518
            }
417
        }
519
        }
520
        
521
        // Return the resulting Principal for our authenticated user
522
        return userPrincipal;
418
    }
523
    }
419
524
420
525
    
421
    // ------------------------------------------------------ Lifecycle Methods
526
    // ------------------------------------------------------ Lifecycle Methods
422
527
423
528
424
    /**
529
    /**
425
     *
530
     *
426
     * Prepare for active use of the public methods of this Component.
531
     * Prepare for active use of the public methods of this <code>Component</code>.
427
     *
532
     *
428
     * @exception LifecycleException if this component detects a fatal error
533
     * @exception <code>LifecycleException</code> if this component detects a fatal error
429
     *  that prevents it from being started
534
     *  that prevents it from being started
430
     */
535
     */
431
    public void start() throws LifecycleException {
536
    public void start() throws LifecycleException {
Lines 437-445 Link Here
437
542
438
543
439
    /**
544
    /**
440
     * Gracefully shut down active use of the public methods of this Component.
545
     * Gracefully shut down active use of the public methods of this <code>Component</code>.
441
     *
546
     *
442
     * @exception LifecycleException if this component detects a fatal error
547
     * @exception <code>LifecycleException</code> if this component detects a fatal error
443
     *  that needs to be reported
548
     *  that needs to be reported
444
     */
549
     */
445
    public void stop() throws LifecycleException {
550
    public void stop() throws LifecycleException {

Return to bug 28631