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
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
00198 lastHttpRequest = request;
00199
00200
00201
00202
00203
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
00231 Principal principal = ((HttpServletRequest) request.getRequest()).getUserPrincipal();
00232
00233
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
00246
00247
00248 if (!hasResourcePermission) {
00249
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
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
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
00334 if (pattern.startsWith("*.") && userPattern.endsWith(pattern.substring(1))) {
00335 foundServlet = true;
00336 continue;
00337 }
00338
00339
00340
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
00352
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
00381 lastHttpRequest = request;
00382
00383
00384
00385
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
00394 Principal principal = ((HttpServletRequest) request).getUserPrincipal();
00395
00396
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
00406 for (int i = 0; i < constraints.length; i++) {
00407 SecurityConstraint constraint = constraints[i];
00408
00409
00410 String userConstraint = constraint.getUserConstraint();
00411
00412
00413 if (userConstraint != null
00414 && (userConstraint.equals(Constants.INTEGRAL_TRANSPORT) || userConstraint
00415 .equals(Constants.CONFIDENTIAL_TRANSPORT))) {
00416
00417
00418 HttpServletRequest hrequest = (HttpServletRequest) request.getRequest();
00419 HttpServletResponse hresponse = (HttpServletResponse) response.getResponse();
00420 int redirectPort = request.getConnector().getRedirectPort();
00421
00422
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
00432 StringBuffer file = new StringBuffer();
00433 String protocol = "https";
00434 String host = hrequest.getServerName();
00435
00436 file.append(protocol).append("://");
00437
00438 file.append(host).append(":").append(redirectPort);
00439
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
00462
00463
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
00483 if (username == null) {
00484 logger.log(BasicLevel.DEBUG, "No username so no authentication");
00485 return null;
00486 }
00487
00488
00489 User user = null;
00490 try {
00491 user = jResource.findUser(username);
00492 } catch (Exception jre) {
00493
00494 logger.log(BasicLevel.ERROR, "Can not find the user : " + jre.getMessage());
00495 return null;
00496 }
00497
00498
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
00591 try {
00592 securityService = (SecurityService) ServiceManager.getInstance().getSecurityService();
00593 } catch (Exception e) {
00594
00595 throw new LifecycleException("can't retrieve Security service");
00596 }
00597
00598
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
00605 super.start();
00606
00607 }
00608
00615 public synchronized void stop() throws LifecycleException {
00616
00617 super.stop();
00618
00619
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 }