JACC.java

00001 
00026 package org.objectweb.jonas.security.realm.web.catalina50;
00027 
00028 import java.io.IOException;
00029 import java.security.Principal;
00030 import java.security.cert.X509Certificate;
00031 import java.util.ArrayList;
00032 
00033 import javax.servlet.http.HttpServletRequest;
00034 import javax.servlet.http.HttpServletResponse;
00035 
00036 import org.apache.catalina.Context;
00037 import org.apache.catalina.HttpRequest;
00038 import org.apache.catalina.HttpResponse;
00039 import org.apache.catalina.LifecycleException;
00040 import org.apache.catalina.deploy.LoginConfig;
00041 import org.apache.catalina.deploy.SecurityConstraint;
00042 import org.apache.catalina.realm.Constants;
00043 import org.apache.catalina.realm.GenericPrincipal;
00044 import org.apache.catalina.realm.RealmBase;
00045 import org.apache.catalina.util.StringManager;
00046 
00047 import org.objectweb.jonas.common.Log;
00048 import org.objectweb.jonas.security.SecurityService;
00049 import org.objectweb.jonas.security.realm.factory.JResource;
00050 import org.objectweb.jonas.security.realm.factory.JResourceException;
00051 import org.objectweb.jonas.security.realm.principals.User;
00052 import org.objectweb.jonas.service.ServiceManager;
00053 import org.objectweb.jonas.web.lib.PermissionManager;
00054 
00055 import org.objectweb.security.context.SecurityContext;
00056 import org.objectweb.security.context.SecurityCurrent;
00057 
00058 import org.objectweb.util.monolog.api.BasicLevel;
00059 import org.objectweb.util.monolog.api.Logger;
00060 
00073 public class JACC extends RealmBase implements Cloneable {
00074 
00078     private static final String NAME = "JRealmJACCCatalina50";
00079 
00083     private static final String INFO = "org.objectweb.jonas.security.realm.JRealmJACCCatalina50/1.0";
00084 
00088     private static StringManager sm = StringManager.getManager(Constants.Package);
00089 
00093     private static Logger logger = null;
00094 
00099     private JResource jResource = null;
00100 
00104     private String resourceName = null;
00105 
00109     private SecurityService securityService = null;
00110 
00114     private PermissionManager permissionManager = null;
00115 
00121     private HttpRequest lastHttpRequest = null;
00122 
00126     private Context context = null;
00127 
00135     public String getInfo() {
00136         return INFO;
00137     }
00138 
00144     public String getResourceName() {
00145         return resourceName;
00146     }
00147 
00153     public void setResourceName(String resourceName) {
00154         this.resourceName = resourceName;
00155 
00156     }
00157 
00163     public void setPermissionManager(PermissionManager permissionManager) {
00164         this.permissionManager = permissionManager;
00165 
00166     }
00167 
00176     public SecurityConstraint[] findSecurityConstraints(HttpRequest request, Context context) {
00177         // Use super Method
00178         return super.findSecurityConstraints(request, context);
00179     }
00180 
00194     public boolean hasResourcePermission(HttpRequest request, HttpResponse response, SecurityConstraint[] constraints,
00195             Context context) throws IOException {
00196 
00197         // Update request
00198         lastHttpRequest = request;
00199 
00200         // --- Use code of RealmBase for the Login / Error pages
00201 
00202         // Specifically allow access to the form login and form error pages
00203         // and the "j_security_check" action
00204         LoginConfig config = context.getLoginConfig();
00205         if (config != null && Constants.FORM_METHOD.equals(config.getAuthMethod())) {
00206             String requestURI = request.getDecodedRequestURI();
00207             String loginPage = context.getPath() + config.getLoginPage();
00208             if (loginPage.equals(requestURI)) {
00209                 if (logger.isLoggable(BasicLevel.DEBUG)) {
00210                     logger.log(BasicLevel.DEBUG, "Allow access to login page " + loginPage);
00211                 }
00212                 return true;
00213             }
00214 
00215             String errorPage = context.getPath() + config.getErrorPage();
00216             if (errorPage.equals(requestURI)) {
00217                 if (logger.isLoggable(BasicLevel.DEBUG)) {
00218                     logger.log(BasicLevel.DEBUG, "Allow access to error page " + errorPage);
00219                 }
00220                 return true;
00221             }
00222             if (requestURI.endsWith(Constants.FORM_ACTION)) {
00223                 if (logger.isLoggable(BasicLevel.DEBUG)) {
00224                     logger.log(BasicLevel.DEBUG, "Allow access to username/password submission");
00225                 }
00226                 return true;
00227             }
00228         }
00229 
00230         // Which user principal have we already authenticated?
00231         Principal principal = ((HttpServletRequest) request.getRequest()).getUserPrincipal();
00232 
00233         // --- End of code from RealmBase class
00234 
00235         String[] roles = null;
00236         String principalName = null;
00237         if (principal instanceof GenericPrincipal) {
00238             roles = ((GenericPrincipal) principal).getRoles();
00239             principalName = principal.getName();
00240         }
00241 
00242         boolean hasResourcePermission = permissionManager.checkWebResourcePermission((HttpServletRequest) request,
00243                 principalName, roles);
00244 
00245         // Need to send HTTP status code as invoke() method of Authenticator
00246         // expect that it is
00247         // done by the realm.
00248         if (!hasResourcePermission) {
00249             // Return a "Forbidden" message denying access to this resource
00250             ((HttpServletResponse) response.getResponse()).sendError(HttpServletResponse.SC_FORBIDDEN, sm
00251                     .getString("realmBase.forbidden"));
00252         }
00253 
00254         return hasResourcePermission;
00255     }
00256 
00268     public boolean hasRole(Principal principal, String role) {
00269 
00270         if ((principal == null) || (role == null) || !(principal instanceof GenericPrincipal)) {
00271             return false;
00272         }
00273 
00274         if (logger.isLoggable(BasicLevel.DEBUG)) {
00275             logger.log(BasicLevel.DEBUG, "Principal = " + principal);
00276             logger.log(BasicLevel.DEBUG, "Role = " + role);
00277         }
00278 
00279         if (context == null) {
00280             logger.log(BasicLevel.ERROR, "Cannot find a servlet name for isUserInRole() as no context was found");
00281             return false;
00282         }
00283 
00284         if (lastHttpRequest == null) {
00285             logger.log(BasicLevel.ERROR, "Cannot find a servlet name for isUserInRole(). No previous request !");
00286             return false;
00287         }
00288         HttpServletRequest httpServletRequest = (HttpServletRequest) lastHttpRequest.getRequest();
00289         String servletName = findServletName(httpServletRequest);
00290         String[] roles = null;
00291         String principalName = null;
00292 
00293         if (principal instanceof GenericPrincipal) {
00294             roles = ((GenericPrincipal) principal).getRoles();
00295             principalName = principal.getName();
00296         }
00297 
00298         boolean hasRole = permissionManager.checkWebRoleRefPermission(httpServletRequest, servletName, principalName, roles, role);
00299         return hasRole;
00300     }
00301 
00310     private String findServletName(HttpServletRequest httpServletRequest) {
00311 
00312         // Pattern of the user (remove path)
00313         String userPattern = httpServletRequest.getRequestURI().substring(httpServletRequest.getContextPath().length());
00314 
00315         if (logger.isLoggable(BasicLevel.DEBUG)) {
00316             logger.log(BasicLevel.DEBUG, "User Pattern = " + userPattern);
00317         }
00318 
00319         String servletName = "";
00320         String[] patterns = context.findServletMappings();
00321         boolean foundServlet = false;
00322         String pattern = "";
00323         int i = 0;
00324 
00325         // Try to search servlet name
00326         while ((i < patterns.length) && !foundServlet) {
00327             pattern = patterns[i];
00328             if (logger.isLoggable(BasicLevel.DEBUG)) {
00329                 logger.log(BasicLevel.DEBUG, "Pattern found = " + pattern);
00330                 logger.log(BasicLevel.DEBUG, "Servlet name for pattern = " + context.findServletMapping(pattern));
00331             }
00332 
00333             // Extension pattern and ends with extension
00334             if (pattern.startsWith("*.") && userPattern.endsWith(pattern.substring(1))) {
00335                 foundServlet = true;
00336                 continue;
00337             }
00338 
00339             // Exact Servlet name (ie pattern = /ServletName and userPattern =
00340             // /ServletName)
00341             if (pattern.equals(userPattern)) {
00342                 foundServlet = true;
00343                 continue;
00344             }
00345 
00346             i++;
00347         }
00348 
00349         if (foundServlet) {
00350             servletName = context.findServletMapping(pattern);
00351             // JSP case. servlet name must be empty as required by JACC
00352             // specification
00353             if (servletName.equals("jsp")) {
00354                 servletName = "";
00355             }
00356             if (logger.isLoggable(BasicLevel.DEBUG)) {
00357                 logger.log(BasicLevel.DEBUG, "Found servlet name = " + servletName);
00358             }
00359         }
00360         return servletName;
00361     }
00362 
00377     public boolean hasUserDataPermission(HttpRequest request, HttpResponse response, SecurityConstraint[] constraints)
00378             throws IOException {
00379 
00380         // Update request
00381         lastHttpRequest = request;
00382 
00383         // ---- Start of copy from RealmBase class ---
00384 
00385         // Validate the request against the user data constraint
00386         if (request.getRequest().isSecure()) {
00387             if (logger.isLoggable(BasicLevel.DEBUG)) {
00388                 logger.log(BasicLevel.DEBUG, "User data constraint already satisfied");
00389             }
00390             return true;
00391         }
00392 
00393         // Which user principal have we already authenticated?
00394         Principal principal = ((HttpServletRequest) request).getUserPrincipal();
00395 
00396         // ---- End of copy from RealmBase class ---
00397 
00398         String[] roles = null;
00399         String principalName = null;
00400         if (principal instanceof GenericPrincipal) {
00401             roles = ((GenericPrincipal) principal).getRoles();
00402             principalName = principal.getName();
00403         }
00404 
00405         // ---- Start of copy from RealmBase class ---
00406         for (int i = 0; i < constraints.length; i++) {
00407             SecurityConstraint constraint = constraints[i];
00408             // Use redirect only if it the transport protocol is integral or
00409             // confidential
00410             String userConstraint = constraint.getUserConstraint();
00411 
00412             // Redirect only if the constraint is INTEGRAL or CONFIDENTIAL !
00413             if (userConstraint != null
00414                     && (userConstraint.equals(Constants.INTEGRAL_TRANSPORT) || userConstraint
00415                             .equals(Constants.CONFIDENTIAL_TRANSPORT))) {
00416                 // Initialize variables we need to determine the appropriate
00417                 // action
00418                 HttpServletRequest hrequest = (HttpServletRequest) request.getRequest();
00419                 HttpServletResponse hresponse = (HttpServletResponse) response.getResponse();
00420                 int redirectPort = request.getConnector().getRedirectPort();
00421 
00422                 // Is redirecting disabled?
00423                 if (redirectPort <= 0) {
00424                     if (logger.isLoggable(BasicLevel.DEBUG)) {
00425                         logger.log(BasicLevel.DEBUG, "SSL redirect is disabled");
00426                     }
00427                     hresponse.sendError(HttpServletResponse.SC_FORBIDDEN, hrequest.getRequestURI());
00428                     return false;
00429                 }
00430 
00431                 // Redirect to the corresponding SSL port
00432                 StringBuffer file = new StringBuffer();
00433                 String protocol = "https";
00434                 String host = hrequest.getServerName();
00435                 // Protocol
00436                 file.append(protocol).append("://");
00437                 // Host with port
00438                 file.append(host).append(":").append(redirectPort);
00439                 // URI
00440                 file.append(hrequest.getRequestURI());
00441                 String requestedSessionId = hrequest.getRequestedSessionId();
00442                 if ((requestedSessionId != null) && hrequest.isRequestedSessionIdFromURL()) {
00443                     file.append(";jsessionid=");
00444                     file.append(requestedSessionId);
00445                 }
00446                 String queryString = hrequest.getQueryString();
00447                 if (queryString != null) {
00448                     file.append('?');
00449                     file.append(queryString);
00450                 }
00451 
00452                 if (logger.isLoggable(BasicLevel.DEBUG)) {
00453                     logger.log(BasicLevel.DEBUG, "Redirecting to " + file.toString());
00454                 }
00455                 hresponse.sendRedirect(file.toString());
00456 
00457                 return false;
00458             }
00459         }
00460 
00461         // ---- End of copy from RealmBase ---
00462 
00463         // If Transport protocol is NONE :
00464         boolean hasUserDataPermission = permissionManager.checkWebUserDataPermission((HttpServletRequest) request,
00465                 principalName,
00466                 roles);
00467         return hasUserDataPermission;
00468 
00469     }
00470 
00480     public Principal authenticate(String username, String credentials) {
00481 
00482         // No authentication can be made with a null username
00483         if (username == null) {
00484             logger.log(BasicLevel.DEBUG, "No username so no authentication");
00485             return null;
00486         }
00487 
00488         // Does a user with this username exist?
00489         User user = null;
00490         try {
00491             user = jResource.findUser(username);
00492         } catch (Exception jre) {
00493             // could not retrieve user
00494             logger.log(BasicLevel.ERROR, "Can not find the user : " + jre.getMessage());
00495             return null;
00496         }
00497 
00498         // User was not found
00499         if (user == null) {
00500             logger.log(BasicLevel.DEBUG, "User " + username + " not found.");
00501             return null;
00502         }
00503 
00504         boolean validated = jResource.isValidUser(user, credentials);
00505         if (!validated) {
00506             logger.log(BasicLevel.ERROR, "The password for the user " + username + " is not valid");
00507             return null;
00508         }
00509 
00510         ArrayList combinedRoles = null;
00511         try {
00512             combinedRoles = jResource.getArrayListCombinedRoles(user);
00513         } catch (JResourceException jre) {
00514             logger.log(BasicLevel.ERROR, jre.getMessage());
00515             return null;
00516         }
00517 
00518         GenericPrincipal principal = new GenericPrincipal(this, user.getName(), user.getPassword(), combinedRoles);
00519         SecurityContext ctx = new SecurityContext(principal.getName(), combinedRoles);
00520         SecurityCurrent current = SecurityCurrent.getCurrent();
00521         current.setSecurityContext(ctx);
00522 
00523         return principal;
00524     }
00525 
00534     public Principal authenticate(X509Certificate[] cert) {
00535         String dn = cert[0].getSubjectDN().getName();
00536         return authenticate(dn, "tomcat");
00537     }
00538 
00544     protected String getName() {
00545         return NAME;
00546     }
00547 
00554     protected String getPassword(String username) {
00555         return null;
00556     }
00557 
00564     protected Principal getPrincipal(String username) {
00565         return null;
00566     }
00567 
00574     public void setContext(Context context) {
00575         this.context = context;
00576     }
00577 
00584     public synchronized void start() throws LifecycleException {
00585 
00586         if (logger == null) {
00587             logger = Log.getLogger(Log.JONAS_SECURITY_PREFIX);
00588         }
00589 
00590         // Get the Security Service
00591         try {
00592             securityService = (SecurityService) ServiceManager.getInstance().getSecurityService();
00593         } catch (Exception e) {
00594             // Can't retrieve Security service
00595             throw new LifecycleException("can't retrieve Security service");
00596         }
00597 
00598         // Get the resource from the security service
00599         jResource = securityService.getJResource(resourceName);
00600         if (jResource == null) {
00601             throw new LifecycleException("Can't retrieve resource '" + resourceName + "' from the security service");
00602         }
00603 
00604         // Perform normal superclass initialization
00605         super.start();
00606 
00607     }
00608 
00615     public synchronized void stop() throws LifecycleException {
00616         // Perform normal superclass finalization
00617         super.stop();
00618 
00619         // Release reference to our resource
00620         jResource = null;
00621     }
00622 
00628     protected void log(String message) {
00629         logger.log(BasicLevel.DEBUG, message);
00630     }
00631 
00638     public Object clone() throws CloneNotSupportedException {
00639         JACC jRealm = new JACC();
00640         jRealm.setResourceName(resourceName);
00641         jRealm.setDebug(debug);
00642         return jRealm;
00643     }
00644 
00645 }

Generated on Tue Feb 15 15:05:23 2005 for JOnAS by  doxygen 1.3.9.1