KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > web > security > RealmAdapter


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23 package com.sun.web.security;
24
25 import com.sun.enterprise.ComponentInvocation;
26 import java.net.MalformedURLException JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.security.Principal JavaDoc;
29 import java.security.cert.X509Certificate JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.logging.Level JavaDoc;
35 import java.util.logging.Logger JavaDoc;
36 import java.util.Set JavaDoc;
37 import javax.security.auth.Subject JavaDoc;
38 import javax.servlet.ServletConfig JavaDoc;
39
40
41 import com.sun.logging.LogDomains;
42 import java.io.IOException JavaDoc;
43 import com.sun.enterprise.deployment.Application;
44 import com.sun.enterprise.deployment.RunAsIdentityDescriptor;
45 import com.sun.enterprise.deployment.WebBundleDescriptor;
46 import com.sun.enterprise.deployment.WebComponentDescriptor;
47 import com.sun.enterprise.deployment.interfaces.SecurityRoleMapper;
48 import com.sun.enterprise.deployment.web.LoginConfiguration;
49
50 import com.sun.enterprise.deployment.runtime.web.SunWebApp;
51 import com.sun.enterprise.security.SecurityContext;
52 import com.sun.enterprise.security.auth.LoginContextDriver;
53 import com.sun.enterprise.security.auth.realm.certificate.CertificateRealm;
54 import com.sun.enterprise.security.jauth.AuthConfig;
55 import com.sun.enterprise.security.jauth.ServerAuthContext;
56 import com.sun.enterprise.security.jauth.AuthParam;
57 import com.sun.enterprise.security.jauth.HttpServletAuthParam;
58 import com.sun.enterprise.security.jauth.PendingException;
59 import com.sun.enterprise.security.jauth.FailureException;
60 import com.sun.enterprise.security.jauth.AuthException;
61 import com.sun.enterprise.webservice.WSSCallbackHandler;
62 import com.sun.enterprise.webservice.monitoring.WebServiceEngineImpl;
63 import com.sun.enterprise.webservice.monitoring.AuthenticationListener;
64 import javax.servlet.http.HttpServlet JavaDoc;
65 import javax.servlet.http.HttpServletRequest JavaDoc;
66 import javax.servlet.http.HttpServletResponse JavaDoc;
67 import org.apache.catalina.Authenticator;
68 import org.apache.catalina.Container;
69 import org.apache.catalina.Context;
70 import org.apache.catalina.HttpRequest;
71 import org.apache.catalina.HttpResponse;
72 import org.apache.catalina.LifecycleException;
73 import org.apache.catalina.Realm;
74 import org.apache.catalina.authenticator.AuthenticatorBase;
75 import org.apache.catalina.deploy.LoginConfig;
76 import org.apache.catalina.deploy.SecurityConstraint;
77 import org.apache.catalina.realm.Constants;
78 import org.apache.catalina.realm.RealmBase;
79 import org.apache.catalina.util.StringManager;
80 import sun.security.x509.X500Name;
81
82 import com.sun.enterprise.Switch;
83 import com.sun.enterprise.admin.monitor.callflow.Agent;
84 import com.sun.enterprise.admin.monitor.callflow.RequestInfo;
85 import com.sun.enterprise.admin.monitor.callflow.ContainerTypeOrApplicationType;
86
87 /**
88  * This is the realm adapter used to authenticate users and authorize
89  * access to web resources. The authenticate method is called by Tomcat
90  * to authenticate users. The hasRole method is called by Tomcat during
91  * the authorization process.
92  * @author Harpreet Singh
93  * @author JeanFrancois Arcand
94  */

95
96 public class RealmAdapter extends RealmBase {
97     private static final String JavaDoc UNCONSTRAINED = "unconstrained";
98     
99     static Logger JavaDoc _logger=LogDomains.getLogger(LogDomains.WEB_LOGGER);
100
101     public static final String JavaDoc SECURITY_CONTEXT = "SecurityContext";
102
103     public static final String JavaDoc BASIC = "BASIC";
104     public static final String JavaDoc FORM = "FORM";
105     private static int MAX_COUNT = 5;
106     private static int SLEEP_TIME = 5000; // milliseconds....
107

108     // name of system property that can be used to define
109
// corresponding default provider for system apps.
110
private static final String JavaDoc SYSTEM_HTTPSERVLET_SECURITY_PROVIDER =
111         "system_httpservlet_security_provider";
112
113     //private String realm = "default";
114
private SecurityRoleMapper mapper = null;
115     private WebBundleDescriptor webDesc = null;
116
117     // BEGIN IASRI 4747594
118
private HashMap JavaDoc runAsPrincipals = null;
119     // END IASRI 4747594
120

121     // required for realm-per-app login
122
private String JavaDoc _realmName = null;
123     /**
124      * Descriptive information about this Realm implementation.
125      */

126     protected static final String JavaDoc name = "J2EE-RI-RealmAdapter";
127     /**
128      * The context Id value needed by the jacc architecture.
129      */

130     private String JavaDoc CONTEXT_ID = null;
131     /**
132      * The string manager for this package.
133      */

134     protected static StringManager sm =
135         StringManager.getManager(Constants.Package);
136
137     protected static StringManager smRA =
138         StringManager.getManager("com.sun.web.security");
139
140     /**
141      * A <code>WebSecurityManager</code> object associated with a CONTEXT_ID
142      */

143     protected volatile WebSecurityManager webSecurityManager = null;
144     
145     /**
146      * The factory used for creating <code>WebSecurityManager</code> object.
147      */

148     protected WebSecurityManagerFactory webSecurityManagerFactory =
149         WebSecurityManagerFactory.getInstance();
150     protected boolean isCurrentURIincluded = false;
151     
152     private ArrayList JavaDoc roles = null;
153        
154     /* the following fields are used to implement a bypass of
155      * FBL related targets
156      */

157     private boolean contextEvaluated = false;
158     private String JavaDoc loginPage = null;
159     private String JavaDoc errorPage = null;
160     
161     private static SecurityConstraint[] emptyConstraints =
162             new SecurityConstraint[] {};
163
164     /**
165      * the default provider id for system apps if one has been established.
166      * the default provider for system apps is established by defining
167      * a system property.
168      */

169     private static String JavaDoc defaultSystemProviderID =
170         getDefaultSystemProviderID();
171
172     private String JavaDoc appID;
173     private boolean isSystemApp;
174     private String JavaDoc securityProviderID;
175     private ServerAuthContext sAC;
176
177     public RealmAdapter() {}
178
179     /**
180      * Create for WS Ejb endpoint authentication.
181      * Roles related data is not available here.
182      */

183     public RealmAdapter(String JavaDoc realmName) {
184         _realmName = realmName;
185     }
186
187     /**
188      * Create the realm adapter. Extracts the role to user/group mapping
189      * from the runtime deployment descriptor.
190      * @param the web bundle deployment descriptor.
191      * @param isSystemApp if the app is a system app.
192      */

193     public RealmAdapter(WebBundleDescriptor descriptor, boolean isSystemApp) {
194         this.isSystemApp = isSystemApp;
195         webDesc = descriptor;
196         Application app = descriptor.getApplication();
197         mapper = app.getRoleMapper();
198         LoginConfiguration loginConfig = descriptor.getLoginConfiguration();
199         _realmName = app.getRealm();
200         if (_realmName == null && loginConfig != null) {
201             _realmName = loginConfig.getRealmName();
202         }
203         // BEGIN IASRI 4747594
204
CONTEXT_ID = WebSecurityManager.getContextID(descriptor);
205         runAsPrincipals = new HashMap JavaDoc();
206         Iterator JavaDoc bundle = webDesc.getWebComponentDescriptorsSet().iterator();
207     
208         while(bundle.hasNext()) {
209             
210             WebComponentDescriptor wcd = (WebComponentDescriptor)bundle.next();
211             RunAsIdentityDescriptor runAsDescriptor = wcd.getRunAsIdentity();
212         
213             if (runAsDescriptor != null) {
214                 String JavaDoc principal = runAsDescriptor.getPrincipal();
215                 String JavaDoc servlet = wcd.getCanonicalName();
216         
217                 if (principal == null || servlet == null) {
218                     _logger.warning("web.realmadapter.norunas");
219                 } else {
220                     runAsPrincipals.put(servlet, principal);
221                     _logger.fine("Servlet "+servlet+
222                      " will run-as: "+principal);
223         }
224         }
225     }
226     // END IASRI 4747594
227

228     this.appID = app.getRegistrationName();
229     this.securityProviderID = getSecurityProviderID();
230     this.sAC = getServerAuthContext();
231     }
232
233     public WebBundleDescriptor getWebDescriptor() {
234         return webDesc;
235     }
236
237     // utility method to get web security anager.
238
// will log warning if the manager is not found in the factory, and
239
// logNull is true.
240
WebSecurityManager getWebSecurityManager(boolean logNull) {
241     if (webSecurityManager == null) {
242         synchronized(this) {
243         webSecurityManager = webSecurityManagerFactory.
244             getWebSecurityManager(CONTEXT_ID);
245         }
246         if (webSecurityManager == null && logNull) {
247         String JavaDoc msg = smRA.getString("realmAdapter.noWebSecMgr", CONTEXT_ID);
248         _logger.warning(msg);
249         }
250     }
251
252     return webSecurityManager;
253     }
254
255     /**
256      * Check if the given principal has the provided role. Returns
257      * true if the principal has the specified role, false otherwise.
258      * @return true if the principal has the specified role.
259      * @param request Request we are processing
260      * @param response Response we are creating
261      * @param the principal
262      * @param the role
263      */

264     //START OF SJSAS 6232464
265
//public boolean hasRole(Principal principal, String role) {
266
public boolean hasRole(HttpRequest request,
267                            HttpResponse response,
268                            Principal JavaDoc principal,
269                            String JavaDoc role) {
270         WebSecurityManager secMgr = getWebSecurityManager(true);
271     if (secMgr == null) {
272         return false;
273     }
274
275         //add HttpResponse and HttpResponse to the parameters, and remove
276
//instance variable currentRequest from this class. References to
277
//this.currentRequest are also removed from other methods.
278
//String servletName = getResourceName( currentRequest.getRequestURI(),
279
// currentRequest.getContextPath());
280
HttpServletRequest JavaDoc hrequest = (HttpServletRequest JavaDoc) request;
281         String JavaDoc servletName = getResourceName( hrequest.getRequestURI(),
282                                               hrequest.getContextPath());
283         //END OF SJSAS 6232464
284

285         // First try with the request.
286
boolean isGranted =
287             secMgr.hasRoleRefPermission(servletName, role, principal);
288         
289         if (!isGranted){
290             // START S1AS8PE 4966609
291
// This case occurs when a direct call is made
292
// to a jsp instead of using the server-name element defined in web.xml
293
servletName = getCanonicalName(hrequest);
294
295             // If we can't find any servletMapping for a resource
296
// (usually a jsp), return false.
297
if (servletName.equalsIgnoreCase(UNCONSTRAINED)){
298                 if(_logger.isLoggable(Level.INFO)){
299                     _logger.log(Level.INFO,
300                         "Unable to find a <servlet-name> element which map: "
301                             + hrequest.getRequestURI());
302                 }
303
304                 /*
305                  * For every security role in the web application add a
306                  * WebRoleRefPermission to the corresponding role. The name of all such
307                  * permissions shall be the empty string, and the actions of each
308                  * permission shall be the corresponding role name. When checking a
309                  * WebRoleRefPermission from a JSP not mapped to a servlet, use a
310                  * permission with the empty string as its name
311                  * and with the argument to isUserInRole as its actions
312                  */

313                 isGranted = secMgr.hasRoleRefPermission("", role, principal);
314
315                 // END S1AS8PE 4966609
316
} else {
317                 isGranted = secMgr.hasRoleRefPermission(servletName,
318                                                                role,
319                                                                principal);
320             }
321         }
322  
323         if(_logger.isLoggable(Level.FINE)) {
324             _logger.fine( "Checking if servlet " + servletName
325                         + " with principal " + principal
326                         + " has role " + role
327                         + " isGranted: " + isGranted);
328         }
329         
330         return isGranted;
331         
332     }
333
334     public void logout() {
335         setSecurityContext(null);
336     }
337
338     /**
339      * Authenticates and sets the SecurityContext in the TLS.
340      * @return the authenticated principal.
341      * @param the user name.
342      * @param the authenticated data.
343      */

344     public Principal JavaDoc authenticate(String JavaDoc username, byte[] authData) {
345         return authenticate(username, new String JavaDoc(authData));
346     }
347
348     /**
349      * Authenticates and sets the SecurityContext in the TLS.
350      * @return the authenticated principal.
351      * @param the user name.
352      * @param the password.
353      */

354     public Principal JavaDoc authenticate(String JavaDoc username, String JavaDoc password) {
355         if (_logger.isLoggable(Level.FINE)){
356             _logger.fine( "Tomcat callback for authenticate user/password");
357             _logger.fine( "usename = " + username);
358         }
359         if(authenticate(username, password, null)) {
360             SecurityContext secCtx = SecurityContext.getCurrent();
361             assert (secCtx != null); // or auth should've failed
362
return new WebPrincipal(username, password, secCtx);
363         } else {
364             return null;
365         }
366     }
367
368     public Principal JavaDoc authenticate(X509Certificate JavaDoc certs[]) {
369         if(authenticate(null, null, certs)) {
370             SecurityContext secCtx = SecurityContext.getCurrent();
371             assert (secCtx != null); // or auth should've failed
372
return new WebPrincipal(certs, secCtx);
373         } else {
374             return null;
375         }
376     }
377
378     /* IASRI 4688449
379        This method was only used by J2EEInstanceListener to set the security
380        context prior to invocations by re-authenticating a previously set
381        WebPrincipal. This is now cached so no need.
382     */

383     public boolean authenticate(WebPrincipal prin) {
384         if (prin.isUsingCertificate()) {
385             return authenticate(null, null, prin.getCertificates());
386         } else {
387             return authenticate(prin.getName(), prin.getPassword(), null);
388         }
389     }
390     
391
392     /**
393      * Authenticates and sets the SecurityContext in the TLS.
394      * @return true if authentication succeeded, false otherwise.
395      * @param the username.
396      * @param the authentication method.
397      * @param the authentication data.
398      */

399     protected boolean authenticate(String JavaDoc username, String JavaDoc password,
400                                    X509Certificate JavaDoc[] certs) {
401
402         SecurityContext.setCurrent(null);
403         String JavaDoc realm_name = null;
404         boolean success = false;
405         try {
406             if (certs != null) {
407                 Subject JavaDoc subject = new Subject JavaDoc();
408                 X509Certificate JavaDoc certificate = certs[0];
409                 X500Name x500Name = (X500Name) certificate.getSubjectDN();
410                 Switch.getSwitch().getCallFlowAgent().addRequestInfo(
411                         RequestInfo.REMOTE_USER, x500Name.getName());
412                 subject.getPublicCredentials().add(x500Name);
413                 LoginContextDriver.login(subject, X500Name.class);
414                 realm_name = CertificateRealm.AUTH_TYPE;
415             } else {
416                 Switch.getSwitch().getCallFlowAgent().addRequestInfo(
417                         RequestInfo.REMOTE_USER, username);
418                 realm_name = _realmName;
419                 LoginContextDriver.login(username, password, realm_name);
420             }
421             success = true;
422         } catch (Exception JavaDoc le) {
423             success = false;
424             if (_logger.isLoggable(Level.WARNING)) {
425                 _logger.warning("Web login failed: " + le.getMessage());
426             }
427         }
428         if(success){
429             if (_logger.isLoggable(Level.FINE)) {
430                 _logger.log(Level.FINE,"Web login succeeded for: " + username);
431             }
432         }
433         if (webDesc!=null && webDesc.hasWebServices()) {
434             WebPrincipal principal = new WebPrincipal(username, password, null);
435             for (AuthenticationListener listener : WebServiceEngineImpl.getInstance().getAuthListeners()) {
436                 if (success) {
437                     listener.authSucess(webDesc, null, principal);
438                 } else {
439                     listener.authFailure(webDesc, null, principal);
440                 }
441             }
442         }
443         return success;
444     }
445     // BEGIN IASRI 4747594
446
/**
447      * Set the run-as principal into the SecurityContext when needed.
448      *
449      * <P>This method will attempt to obtain the name of the servlet from
450      * the ComponentInvocation. Note that there may not be one since this
451      * gets called also during internal processing (not clear..) not just
452      * part of servlet requests. However, if it is not a servlet request
453      * there is no need (or possibility) to have a run-as setting so no
454      * further action is taken.
455      *
456      * <P>If the servlet name is present the runAsPrincipals cache is
457      * checked to find the run-as principal to use (if any). If one is set,
458      * the SecurityContext is switched to this principal.
459      *
460      * @param inv The invocation object to process.
461      *
462      */

463     public void preSetRunAsIdentity (ComponentInvocation inv) {
464
465         String JavaDoc name=this.getServletName(inv);
466         if (name == null) {
467             return;
468         }
469
470         String JavaDoc runAs = (String JavaDoc)runAsPrincipals.get(name);
471         
472         if (runAs != null) {
473             // The existing SecurityContext is saved - however, this seems
474
// meaningless - see bug 4757733. For now, keep it unchanged
475
// in case there are some dependencies elsewhere in RI.
476
SecurityContext old = getSecurityContext();
477             inv.setOldSecurityContext(old);
478
479             // Set the run-as principal into SecurityContext
480
loginForRunAs(runAs);
481             
482             if (_logger.isLoggable(Level.FINE)) {
483                 _logger.fine("run-as principal for " + name +
484                              " set to: "+ runAs);
485             }
486         }
487     }
488
489
490     /**
491      * Obtain servlet name from invocation.
492      *
493      * <P>In order to obtain the servlet name the following must be true:
494      * The ComponentInvocation contains a 'class' of type HttpServlet, which
495      * contains a valid ServletConfig object. This method returns the
496      * value returned by getServletName() on the ServletConfig. If the above
497      * is not met, null is returned.
498      *
499      * @param inv The invocation object to process.
500      * @return Servlet name or null.
501      *
502      */

503     private String JavaDoc getServletName(ComponentInvocation inv)
504     {
505         Object JavaDoc invInstance = inv.getInstance();
506         
507         if (invInstance instanceof HttpServlet JavaDoc) {
508
509             HttpServlet JavaDoc thisServlet = (HttpServlet JavaDoc)invInstance;
510             ServletConfig JavaDoc svc = thisServlet.getServletConfig();
511
512             if (svc != null) {
513                 return thisServlet.getServletName();
514             }
515         }
516         return null;
517     }
518
519
520     /**
521      * Attempts to restore old SecurityContext (but fails).
522      *
523      * <P>In theory this method seems to attempt to check if a run-as
524      * principal was set by preSetRunAsIdentity() (based on the indirect
525      * assumption that if the servlet in the given invocation has a run-as
526      * this must've been the case). If so, it retrieves the oldSecurityContext
527      * from the invocation object and set it in the SecurityContext.
528      *
529      * <P>The problem is that the invocation object is not the same object
530      * as was passed in to preSetRunAsIdentity() so it will never contain
531      * the right info - see bug 4757733.
532      *
533      * <P>In practice it means this method only ever sets the
534      * SecurityContext to null (if run-as matched) or does nothing. In
535      * particular note the implication that it <i>will</i> be set to
536      * null after a run-as invocation completes. This behavior will be
537      * retained for the time being for consistency with RI. It must be fixed
538      * later.
539      *
540      * @param inv The invocation object to process.
541      *
542      */

543     public void postSetRunAsIdentity (ComponentInvocation inv){
544
545         String JavaDoc name=this.getServletName(inv);
546         if (name == null) {
547             return;
548         }
549
550         String JavaDoc runAs = (String JavaDoc)runAsPrincipals.get(name);
551         if (runAs != null) {
552             setSecurityContext (inv.getOldSecurityContext ()); // always null
553

554         }
555     }
556     // END IASRI 4747594
557

558     private void loginForRunAs (String JavaDoc principal) {
559     LoginContextDriver.loginPrincipal (principal, _realmName);
560     }
561     private SecurityContext getSecurityContext (){
562         return SecurityContext.getCurrent ();
563     }
564     private void setSecurityContext (SecurityContext sc){
565         SecurityContext.setCurrent (sc);
566     }
567
568     protected String JavaDoc getPassword(String JavaDoc username) {
569         throw new IllegalStateException JavaDoc("Should not reach here");
570     }
571
572     protected Principal JavaDoc getPrincipal(String JavaDoc username) {
573         throw new IllegalStateException JavaDoc("Should not reach here");
574     }
575     
576     //START OF IASRI 4809144
577
/**
578      * This method is added to create a Principal based on the username only.
579      * Hercules stores the username as part of authentication failover and
580      * needs to create a Principal based on username only <sridhar.satuloori@sun.com>
581      * @param username
582      * @return Principal for the user username
583      * HERCULES:add
584      */

585     public Principal JavaDoc createFailOveredPrincipal(String JavaDoc username){
586         _logger.log(Level.FINEST,"IN createFailOveredPrincipal ("+username+")");
587         //set the appropriate security context
588
loginForRunAs(username);
589         SecurityContext secCtx = SecurityContext.getCurrent();
590          _logger.log(Level.FINE,"Security context is "+secCtx);
591         assert (secCtx != null);
592         Principal JavaDoc principal = new WebPrincipal(username, null, secCtx);
593         _logger.log(Level.INFO,"Principal created for FailOvered user "+principal);
594         return principal;
595     }
596     //END OF IASRI 4809144
597

598     /**
599      * Perform access control based on the specified authorization constraint.
600      * Return <code>true</code> if this constraint is satisfied and processing
601      * should continue, or <code>false</code> otherwise.
602      *
603      * @param request Request we are processing
604      * @param response Response we are creating
605      * @param constraint Security constraint we are enforcing
606      * @param The Context to which client of this class is attached.
607      *
608      * @exception IOException if an input/output error occurs
609      */

610     public boolean hasResourcePermission(HttpRequest request,
611                                          HttpResponse response,
612                                          SecurityConstraint[] constraints,
613                                          Context context)
614         throws IOException JavaDoc {
615         boolean isGranted = false;
616         try {
617             isGranted = invokeWebSecurityManager(
618                 request, response, constraints);
619         } catch(IOException JavaDoc iex) {
620             throw iex;
621         } catch(Throwable JavaDoc ex) {
622             ((HttpServletResponse JavaDoc) response.getResponse()).sendError
623                     (HttpServletResponse.SC_SERVICE_UNAVAILABLE);
624             response.setDetailMessage(sm.getString("realmBase.forbidden"));
625             return isGranted;
626         }
627           
628         if ( isGranted ){
629             return isGranted;
630         } else {
631             ((HttpServletResponse JavaDoc) response.getResponse()).sendError
632                     (HttpServletResponse.SC_FORBIDDEN);
633             response.setDetailMessage(sm.getString("realmBase.forbidden"));
634             return isGranted;
635         }
636     }
637     
638     /**
639      * Invokes WebSecurityManager to perform access control check.
640      * Return <code>true</code> if permission is granted, or <code>false</code>
641      * otherwise.
642      *
643      * @param request Request we are processing
644      * @param response Response we are creating
645      * @param constraint Security constraint we are enforcing
646      *
647      * @exception IOException if an input/output error occurs
648      */

649     private boolean invokeWebSecurityManager(HttpRequest request,
650                                          HttpResponse response,
651                                          SecurityConstraint[] constraints)
652                                          throws IOException JavaDoc {
653         HttpServletRequest JavaDoc hrequest = (HttpServletRequest JavaDoc)request;
654                 
655         if ( hrequest.getServletPath() == null){
656             request.setServletPath( getResourceName( hrequest.getRequestURI(),
657                     hrequest.getContextPath()));
658         }
659                 
660         if(_logger.isLoggable(Level.FINE))
661             _logger.fine("[Web-Security] [ hasResourcePermission ] Principal: "
662                 + hrequest.getUserPrincipal() + " ContextPath: " + hrequest.getContextPath());
663
664         WebSecurityManager secMgr = getWebSecurityManager(true);
665     if (secMgr == null) {
666         return false;
667     }
668         return secMgr.hasResourcePermission(hrequest);
669     }
670     
671     /**
672      * Enforce any user data constraint required by the security constraint
673      * guarding this request URI. Return <code>true</code> if this constraint
674      * was not violated and processing should continue, or <code>false</code>
675      * if we have created a response already.
676      *
677      * @param request Request we are processing
678      * @param response Response we are creating
679      * @param constraint Security constraint being checked
680      *
681      * @exception IOException if an input/output error occurs
682      */

683     public boolean hasUserDataPermission(HttpRequest request,
684                                          HttpResponse response,
685                                          SecurityConstraint[] constraints) throws IOException JavaDoc {
686         HttpServletRequest JavaDoc hrequest = (HttpServletRequest JavaDoc)request;
687         if ( hrequest.getServletPath() == null){
688             request.setServletPath(
689                 getResourceName( hrequest.getRequestURI(),
690                                 hrequest.getContextPath()));
691         }
692        
693         if(_logger.isLoggable(Level.FINE)){
694             _logger.fine("[Web-Security][ hasUserDataPermission ] Principal: "
695                         + hrequest.getUserPrincipal()
696                         + " ContextPath: "
697                         + hrequest.getContextPath());
698         }
699         
700         if (request.getRequest().isSecure()) {
701             if(_logger.isLoggable(Level.FINE))
702                 _logger.fine("[Web-Security] request.getRequest().isSecure(): " + request.getRequest().isSecure());
703             return true;
704         }
705         
706         WebSecurityManager secMgr = getWebSecurityManager(true);
707     if (secMgr == null) {
708         return false;
709     }
710
711         int isGranted = 0;
712         try {
713             isGranted = secMgr.hasUserDataPermission(hrequest);
714         } catch (IllegalArgumentException JavaDoc e) {
715             //end the request after getting IllegalArgumentException while checking
716
//user data permission
717
String JavaDoc msg = sm.getString("realmBase.badRequest", e.getMessage());
718             _logger.warning(msg);
719             if(_logger.isLoggable(Level.FINE)) {
720                 _logger.log(Level.FINE, msg, e);
721             }
722             ((HttpServletResponse JavaDoc) response.getResponse()).sendError
723                 (HttpServletResponse.SC_BAD_REQUEST, msg);
724             return false;
725         }
726         
727         // Only redirect if we are sure the user will be granted.
728
// See bug 4947698
729

730         // This method will return:
731
// 1 - if granted
732
// 0 - if not granted
733
// -1 - if the current transport is not granted, but a redirection can occur
734
// so the grand will succeed.
735
if ( isGranted == -1 ){
736             if(_logger.isLoggable(Level.FINE))
737                 _logger.fine( "[Web-Security] redirecting using SSL");
738             return redirect(request, response);
739         }
740         
741         if (isGranted == 0){
742             ((HttpServletResponse JavaDoc) response.getResponse()).sendError
743                 (HttpServletResponse.SC_FORBIDDEN,
744                     sm.getString("realmBase.forbidden"));
745             return false;
746         }
747
748         return true;
749      }
750     
751     private boolean redirect(HttpRequest request, HttpResponse response) throws IOException JavaDoc{
752         // Initialize variables we need to determine the appropriate action
753
HttpServletRequest JavaDoc hrequest =
754             (HttpServletRequest JavaDoc) request.getRequest();
755         HttpServletResponse JavaDoc hresponse =
756             (HttpServletResponse JavaDoc) response.getResponse();
757         int redirectPort = request.getConnector().getRedirectPort();
758
759         // Is redirecting disabled?
760
if (redirectPort <= 0) {
761             if(_logger.isLoggable(Level.INFO))
762                 _logger.fine("[Web-Security] SSL redirect is disabled");
763
764             hresponse.sendError
765                 (HttpServletResponse.SC_FORBIDDEN, hrequest.getRequestURI());
766             return (false);
767         }
768        
769         String JavaDoc protocol = "https";
770         String JavaDoc host = hrequest.getServerName();
771         StringBuffer JavaDoc file = new StringBuffer JavaDoc(hrequest.getRequestURI());
772         String JavaDoc requestedSessionId = hrequest.getRequestedSessionId();
773         if ((requestedSessionId != null) &&
774             hrequest.isRequestedSessionIdFromURL()) {
775             file.append(";jsessionid=");
776             file.append(requestedSessionId);
777         }
778         String JavaDoc queryString = hrequest.getQueryString();
779         if (queryString != null) {
780             file.append('?');
781             file.append(queryString);
782         }
783         URL JavaDoc url = null;
784         try {
785             url = new URL JavaDoc(protocol, host, redirectPort, file.toString());
786             hresponse.sendRedirect(url.toString());
787             return (false);
788         } catch (MalformedURLException JavaDoc e) {
789             hresponse.sendError
790                 (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
791                  hrequest.getRequestURI());
792             return (false);
793         }
794     }
795
796     //START SJSAS 6232464
797
//pass in HttpServletResponse instead of saving it as instance variable
798
//private String getCanonicalName(){
799
private String JavaDoc getCanonicalName(HttpServletRequest JavaDoc currentRequest){
800     //END SJSAS 6232464
801
String JavaDoc servletUri = "";
802         String JavaDoc currentUri = "";
803         String JavaDoc aliasUri = "";
804         String JavaDoc currentUriExtension = "";
805         String JavaDoc aliasUriExtension = "";
806         boolean isAliasExists = false;
807         for (Iterator JavaDoc itr = webDesc.getWebComponentDescriptorsSet().iterator(); itr.hasNext();) {
808             WebComponentDescriptor webComponentDescriptor = (WebComponentDescriptor)itr.next();
809             servletUri = webComponentDescriptor.getWebComponentImplementation();
810
811             currentUri = getResourceName( currentRequest.getRequestURI(), currentRequest.getContextPath());
812             currentUriExtension = getExtension(currentUri);
813             
814             // First check the servlet mapping
815
for (Iterator JavaDoc i = webComponentDescriptor.getUrlPatternsSet().iterator(); i.hasNext();) {
816                 aliasUri = i.next().toString();
817                 aliasUriExtension = getExtension(aliasUri);
818                 
819                 if (aliasUri.equalsIgnoreCase(currentUri)){
820                     isAliasExists = true;
821                     break;
822                 }
823                 
824                 if (aliasUriExtension.equalsIgnoreCase(currentUriExtension)
825                         && aliasUri.equalsIgnoreCase("*" + aliasUriExtension)){
826                     isAliasExists = true;
827                     break;
828                 }
829             }
830
831             if (currentUri.equalsIgnoreCase(servletUri)
832                     || isAliasExists){
833                 return webComponentDescriptor.getCanonicalName();
834             }
835         }
836         return UNCONSTRAINED;
837     }
838     
839     private String JavaDoc getResourceName(String JavaDoc uri, String JavaDoc contextPath){
840         try{
841             return uri.substring(contextPath.length());
842         } catch (java.lang.Exception JavaDoc ex){
843             return "";
844         }
845     }
846     
847     private String JavaDoc getExtension(String JavaDoc uri){
848         try{
849             return uri.substring(uri.lastIndexOf("."));
850         } catch (java.lang.Exception JavaDoc ex){
851             // don't use the cache and let jacc create the permission.
852
return "";
853         }
854     }
855     
856
857     /**
858      * Return a short name for this Realm Adapter implementation.
859      */

860     protected String JavaDoc getName() {
861         return (this.name);
862     }
863
864      /**
865       * Return the name of the realm this RealmAdapter uses.
866       *
867       * @return realm name
868       *
869       */

870      public String JavaDoc getRealmName() {
871          return _realmName;
872      }
873
874     public void setRealmName(String JavaDoc realmName){
875         // do nothing since this is done when initializing the Realm.
876
}
877
878     //START SJSAS 6232464 6202703
879
/**
880      * Returns null
881      * 1. if there are no security constrainst defined on any of the web
882      * resources within the context, or
883      * 2. if the target is a form login related page or target.
884      *
885      * otherwise return an empty array of SecurityConstraint.
886      */

887     public SecurityConstraint[] findSecurityConstraints(HttpRequest request,
888                             Context context) {
889     WebSecurityManager secMgr = getWebSecurityManager(false);
890  
891     if (secMgr != null && secMgr.hasNoConstrainedResources()) {
892         return null;
893     }
894  
895     SecurityConstraint[] constraints = RealmAdapter.emptyConstraints;
896     synchronized (this) {
897         if (!contextEvaluated) {
898         LoginConfig config = context.getLoginConfig();
899         if ((config != null) &&
900             (Constants.FORM_METHOD.equals(config.getAuthMethod()))) {
901             loginPage = config.getLoginPage();
902             errorPage = config.getErrorPage();
903             contextEvaluated = true;
904         }
905         }
906     }
907
908         // allow access to form login related pages and targets
909
// and the "j_security_check" action
910
if (loginPage != null || errorPage != null) {
911             String JavaDoc requestURI = request.getRequestPathMB().toString();
912             if(_logger.isLoggable(Level.FINE))
913                 _logger.fine("[Web-Security] requestURI: " + requestURI +
914                         " loginPage: " + loginPage);
915             if (loginPage != null && loginPage.equals(requestURI)) {
916                 if(_logger.isLoggable(Level.FINE))
917                     _logger.fine(" Allow access to login page " + loginPage);
918                 constraints = null;
919             }
920             else if (errorPage != null && errorPage.equals(requestURI)) {
921                 if(_logger.isLoggable(Level.FINE))
922                     _logger.fine(" Allow access to error page " + errorPage);
923                 constraints = null;
924             }
925
926             else if (requestURI.endsWith(Constants.FORM_ACTION)) {
927         _logger.fine(" Allow access to username/password submission");
928                 constraints = null;
929             }
930         }
931     return constraints;
932     }
933     //END SJSAS 6232464 6202703
934

935     //START SJSAS 6202703
936
/**
937      * Checks whether or not authentication is needed.
938      * Returns an int, one of AUTHENTICATE_NOT_NEEDED, AUTHENTICATE_NEEDED,
939      * or AUTHENTICATED_NOT_AUTHORIZED
940      *
941      * @param request Request we are processing
942      * @param response Response we are creating
943      * @param constraints Security constraint we are enforcing
944      * @param disableProxyCaching whether or not to disable proxy caching for
945      * protected resources.
946      * @param securePagesWithPragma true if we add headers which
947      * are incompatible with downloading office documents in IE under SSL but
948      * which fix a caching problem in Mozilla.
949      *
950      * @exception IOException if an input/output error occurs
951      */

952     public int preAuthenticateCheck(HttpRequest request,
953                                     HttpResponse response,
954                                     SecurityConstraint[] constraints,
955                                     boolean disableProxyCaching,
956                                     boolean securePagesWithPragma)
957         throws IOException JavaDoc {
958         boolean isGranted = false;
959         try {
960             isGranted = invokeWebSecurityManager(
961                 request, response, constraints);
962         } catch(IOException JavaDoc iex) {
963             throw iex;
964         } catch(Throwable JavaDoc ex) {
965             ((HttpServletResponse JavaDoc) response.getResponse()).sendError
966                     (HttpServletResponse.SC_SERVICE_UNAVAILABLE);
967             response.setDetailMessage(sm.getString("realmBase.forbidden"));
968             return Realm.AUTHENTICATED_NOT_AUTHORIZED;
969         }
970         
971         if(isGranted) {
972             HashMap JavaDoc sharedState = null;
973             boolean delegateSessionMgmt = false;
974         if (this.sAC != null) {
975                 sharedState = new HashMap JavaDoc();
976                 try {
977                     delegateSessionMgmt = this.sAC.managesSessions(sharedState);
978                 } catch (AuthException ae) {
979                     delegateSessionMgmt = false;
980                 }
981             }
982             if (delegateSessionMgmt) {
983                 if (validate(request,response,null,null,sharedState)){
984                     disableProxyCaching(request, response, disableProxyCaching,
985                         securePagesWithPragma);
986                 }
987             } else if( ((HttpServletRequest JavaDoc) request).getUserPrincipal() != null) {
988                 disableProxyCaching(request, response, disableProxyCaching,
989                     securePagesWithPragma);
990             }
991             return Realm.AUTHENTICATE_NOT_NEEDED;
992         } else if(((HttpServletRequest JavaDoc) request).getUserPrincipal() != null){
993             ((HttpServletResponse JavaDoc) response.getResponse()).sendError
994                     (HttpServletResponse.SC_FORBIDDEN);
995             response.setDetailMessage(sm.getString("realmBase.forbidden"));
996             return Realm.AUTHENTICATED_NOT_AUTHORIZED;
997         } else {
998             disableProxyCaching(request, response, disableProxyCaching,securePagesWithPragma);
999             return Realm.AUTHENTICATE_NEEDED;
1000        }
1001    }
1002    
1003    
1004    /**
1005     * Authenticates the user making this request, based on the specified
1006     * login configuration. Return <code>true</code> if any specified
1007     * requirements have been satisfied, or <code>false</code> if we have
1008     * created a response challenge already.
1009     *
1010     * @param request Request we are processing
1011     * @param response Response we are creating
1012     * @param context The Context to which client of this class is attached.
1013     * @param authenticantion the current authenticator.
1014     * @exception IOException if an input/output error occurs
1015     */

1016    public boolean invokeAuthenticateDelegate(HttpRequest request,
1017                                              HttpResponse response,
1018                                              Context context,
1019                                              Authenticator authenticator)
1020    throws IOException JavaDoc {
1021
1022        boolean result = false;
1023    LoginConfig config = context.getLoginConfig();
1024        if (this.sAC != null) {
1025        //JSR196 is enabled for this application
1026
HashMap JavaDoc sharedState = new HashMap JavaDoc();
1027            result = validate(request,response,config,authenticator,sharedState);
1028        } else {
1029            //jsr196 is not enabled. Use the current authenticator.
1030
result = ((AuthenticatorBase) authenticator).authenticate(
1031                request, response, config);
1032        }
1033        return result;
1034    }
1035
1036    private ServerAuthContext getServerAuthContext() {
1037        ServerAuthContext rvalue = null;
1038    String JavaDoc providerID = this.securityProviderID;
1039        // ensure that default provider from config system
1040
// is not applied to system apps
1041
if (this.isSystemApp && providerID == null) {
1042            providerID = defaultSystemProviderID;
1043        if (providerID == null) {
1044        return null;
1045        }
1046        }
1047
1048    AuthConfig authConfig = AuthConfig.getAuthConfig();
1049    try {
1050        rvalue = authConfig.getServerAuthContext
1051        ("HttpServlet",
1052         providerID,null,null,WSSCallbackHandler.getInstance());
1053    } catch (AuthException ae) {
1054        _logger.log(Level.SEVERE,
1055                "Container-auth: fail to get ServerAuthContext for app " +
1056        appID + ", with security provider id " + providerID, ae);
1057    }
1058    return rvalue;
1059    }
1060
1061    private boolean validate(HttpRequest request,
1062                 HttpResponse response,
1063                 LoginConfig config,
1064                 Authenticator authenticator,
1065                             Map JavaDoc sharedState) throws IOException JavaDoc {
1066
1067        HttpServletRequest JavaDoc req = (HttpServletRequest JavaDoc)request;
1068        HttpServletResponse JavaDoc res = (HttpServletResponse JavaDoc)response;
1069
1070        Subject JavaDoc subject = new Subject JavaDoc();
1071
1072        HttpServletAuthParam param = new HttpServletAuthParam(req,res);
1073
1074        boolean rvalue = false;
1075        try{
1076            this.sAC.validateRequest((AuthParam)param, subject, sharedState);
1077            rvalue = true;
1078        } catch(PendingException pe){
1079            _logger.log(Level.FINE,"Container-auth: validation incomplete",pe);
1080        } catch(FailureException fe){
1081            _logger.log(Level.FINE,"Container-auth: Error validating request ",fe);
1082        } catch (AuthException ae) {
1083            _logger.log(Level.FINE,"Container-auth: http msg authentication fail",ae);
1084    }
1085
1086        if (rvalue) {
1087            Set JavaDoc principalSet = subject.getPrincipals();
1088            // must be at least one new principal to establish
1089
// non-default security contex
1090
if (principalSet != null && !principalSet.isEmpty()) {
1091        Principal JavaDoc p = (Principal JavaDoc)principalSet.iterator().next();
1092        SecurityContext ctx = new SecurityContext(p.getName(),subject);
1093        WebPrincipal wp = new WebPrincipal(p,ctx);
1094        try {
1095            if (this.sAC.managesSessions(sharedState)) {
1096            // registration (via proxy) does not occur
1097
// if context manages sessions
1098
// record authentication information in the request
1099
request.setAuthType(PROXY_AUTH_TYPE);
1100            request.setUserPrincipal(wp);
1101            } else {
1102            AuthenticatorProxy proxy =
1103                new AuthenticatorProxy(authenticator,wp);
1104            proxy.authenticate(request,response,config);
1105            }
1106        } catch (LifecycleException le) {
1107            _logger.log(Level.SEVERE,"[Web-Security] unable to register session",le);
1108        } catch (AuthException ae) {
1109            _logger.log(Level.SEVERE,"[Web-Security] unable to register session",ae);
1110        }
1111        } else {
1112        rvalue = false;
1113        }
1114    }
1115        return rvalue;
1116    }
1117    
1118    /**
1119     * gets the authentication provider id from the sun-specific deployment
1120     * descriptor (if one is defined there).
1121     * @return a String provider id, or null.
1122     */

1123    private String JavaDoc getSecurityProviderID() {
1124    SunWebApp sunWebApp = webDesc.getSunDescriptor();
1125    String JavaDoc rvalue = (sunWebApp != null ? sunWebApp.getAttributeValue
1126        (sunWebApp.HTTPSERVLET_SECURITY_PROVIDER) : null);
1127    return rvalue;
1128    }
1129
1130    /**
1131     * get the default provider id for system apps if one has been established.
1132     * the default provider for system apps is established by defining
1133     * a system property.
1134     * @return the provider id or null.
1135     */

1136    private static String JavaDoc getDefaultSystemProviderID() {
1137    String JavaDoc p = System.getProperty(SYSTEM_HTTPSERVLET_SECURITY_PROVIDER);
1138    if (p != null) {
1139        p = p.trim();
1140        if (p.length() == 0) {
1141        p = null;
1142        }
1143    }
1144    return p;
1145    }
1146
1147    private static String JavaDoc PROXY_AUTH_TYPE = "PLUGGABLE_PROVIDER";
1148
1149    // inner class extends AuthenticatorBase such that session registration
1150
// of webtier can be invoked by RealmAdapter after authentication
1151
// by authentication module.
1152

1153    class AuthenticatorProxy extends AuthenticatorBase {
1154
1155    AuthenticatorBase authBase;
1156    Principal JavaDoc principal;
1157
1158    public boolean getCache() {
1159        return authBase.getCache();
1160    }
1161
1162    public Container getContainer() {
1163        return authBase.getContainer();
1164    }
1165
1166    AuthenticatorProxy(Authenticator authenticator, Principal JavaDoc p)
1167        throws LifecycleException
1168    {
1169
1170        this.authBase = (AuthenticatorBase) authenticator;
1171        this.principal = p;
1172
1173        setCache(authBase.getCache());
1174        setContainer(authBase.getContainer());
1175        start(); //finds sso valve and sets its value in proxy
1176
}
1177
1178    public boolean
1179    authenticate(HttpRequest request,
1180             HttpResponse response,
1181             LoginConfig config) throws IOException JavaDoc
1182
1183    {
1184        register(request,response,this.principal,
1185             RealmAdapter.PROXY_AUTH_TYPE,
1186             this.principal.getName(),null);
1187        return true;
1188    }
1189    }
1190}
1191
Popular Tags