/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.web.tomcat.security;
import java.io.IOException;
import java.security.Principal;
import java.security.acl.Group;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.security.auth.Subject;
import javax.security.auth.message.MessageInfo;
import javax.security.auth.message.AuthStatus;
import javax.security.jacc.PolicyContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.Context;
import org.apache.catalina.authenticator.Constants;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.deploy.LoginConfig;
import org.apache.catalina.deploy.SecurityConstraint;
import org.apache.catalina.realm.RealmBase;
import org.jboss.logging.Logger;
import org.jboss.mx.util.MBeanServerLocator;
import org.jboss.security.AuthorizationManager;
import org.jboss.security.GeneralizedAuthenticationManager;
import org.jboss.security.SimplePrincipal;
import org.jboss.security.auth.message.GenericMessageInfo;
import org.jboss.security.authorization.AuthorizationContext;
import org.jboss.security.authorization.resources.WebResource;
//$Id: JBossExtendedSecurityMgrRealm.java 97697 2009-12-10 15:49:13Z remy.maucherat@jboss.com $
/**
* Tomcat security realm that has the request/response messages
* available during authentication decisions
* @author <a href="mailto:Anil.Saldhana@jboss.org">Anil Saldhana</a>
* @since May 24, 2006
* @version $Revision: 97697 $
*/
public class JBossExtendedSecurityMgrRealm extends JBossSecurityMgrRealm
implements ExtendedRealm
{
private static Logger logger = Logger.getLogger(JBossExtendedSecurityMgrRealm.class);
protected ObjectName authenticationManagerService = null;
protected ObjectName authorizationManagerService = null;
public JBossExtendedSecurityMgrRealm()
{
try
{
this.authenticationManagerService = new ObjectName("jboss.security:service=JASPISecurityManager");
this.authorizationManagerService = new ObjectName("jboss.security:service=AuthorizationManager");
}
catch(JMException jme)
{
log.error("Error in instantiating object names:",jme);
}
}
/**
* Allow injection of the object name for the authentication
* manager jmx service
*
* @param oname Object Name
*/
public void setAuthenticationManagerService(String oname)
{
ObjectName temp = null;
try
{
temp = new ObjectName(oname);
}
catch(JMException jme)
{
log.error("Error in setAuthenticationManagerService:",jme);
}
if(temp != null)
this.authenticationManagerService = temp;
}
/**
* Allow injection of the object name for the authorization
* manager jmx service
*
* @param oname Object Name
*/
public void setAuthorizationManagerService(String oname)
{
ObjectName temp = null;
try
{
temp = new ObjectName(oname);
}
catch(JMException jme)
{
log.error("Error in setAuthorizationManagerService:",jme);
}
if(temp != null)
this.authorizationManagerService = temp;
}
/**
* @see ExtendedRealm#authenticate(Request, Response, LoginConfig)
*/
public Principal authenticate(Request request, HttpServletResponse response,
LoginConfig config) throws Exception
{
log.debug("ExtendedSecurityMgrRealm:authenticate");
MessageInfo authParam = new GenericMessageInfo(request, request.getResponse());
GeneralizedAuthenticationManager gam = getAuthenticationManager();
Subject clientSubject = new Subject();
Subject serviceSubject = new Subject();
Map sharedState = getSharedState(request,config);
AuthStatus status = AuthStatus.FAILURE;
while(!status.equals(AuthStatus.SEND_CONTINUE))
{
status = gam.validateRequest(authParam, clientSubject, serviceSubject);
if(status.equals(AuthStatus.FAILURE))
throw new SecurityException("Authentication failed");
}
Principal authenticatedPrincipal = this.getAuthenticatedPrincipal(clientSubject);
return null;
/*
AuthorizationManager authzManager = getAuthorizationManager();
Principal callerPrincipal = getAuthenticationManager().getPrincipal(authenticatedPrincipal);
return getCachingPrincipal(authzManager, authenticatedPrincipal, callerPrincipal, null, clientSubject);
*/
}
/**
* @see RealmBase#hasResourcePermission(org.apache.catalina.connector.Request,
* org.apache.catalina.connector.Response, org.apache.catalina.deploy.SecurityConstraint[], org.apache.catalina.Context)
*/
public boolean hasResourcePermission(Request request, Response response,
SecurityConstraint[] constraints, Context context) throws IOException
{
boolean isAuthorized = super.hasResourcePermission(request, response,
constraints, context);
log.debug("Super class has authorized="+isAuthorized);
AuthorizationManager authzManager = null;
try
{
authzManager = this.getAuthorizationManager();
}
catch(Exception e)
{
log.error("Error obtaining Authorization Manager:",e);
}
final HashMap map = new HashMap();
map.put("catalina.request",request);
map.put("catalina.constraints",constraints);
map.put("catalina.context", context);
map.put("authorizationManager",authzManager);
WebResource resource = new WebResource(map);
try
{
int check = authzManager.authorize(resource);
isAuthorized = (check == AuthorizationContext.PERMIT);
}
catch (Exception e)
{
isAuthorized = false;
log.error("Error in authorization:",e);
}
log.debug("Final Authorization Result="+isAuthorized);
if(!isAuthorized)
{
((HttpServletResponse)response).setStatus(HttpServletResponse.SC_FORBIDDEN);
}
return isAuthorized;
}
private Map getSharedState(Request request, LoginConfig config)
{
Map map = new HashMap();
if(config.getAuthMethod().equals(HttpServletRequest.FORM_AUTH))
{
map.put("javax.security.auth.login.name",
getPrincipal(request.getParameter(Constants.FORM_USERNAME)));
map.put("javax.security.auth.login.password",
request.getParameter(Constants.FORM_PASSWORD));
}
return map;
}
/**
* Create the session principal tomcat will cache to avoid callouts to this
* Realm.
*
* @param authzManager - the AuthorizationManager
* @param authPrincipal - the principal used for authentication and stored in
* the security manager cache
* @param callerPrincipal - the possibly different caller principal
* representation of the authenticated principal
* @param credential - the credential used for authentication
* @return the tomcat session principal wrapper
*/
protected Principal getCachingPrincipal(AuthorizationManager authzManager,
Principal authPrincipal, Principal callerPrincipal, Object credential,
Subject subject)
{
// Cache the user roles in the principal
Set userRoles = authzManager.getUserRoles(authPrincipal);
ArrayList roles = new ArrayList();
if (userRoles != null)
{
Iterator iterator = userRoles.iterator();
while (iterator.hasNext())
{
Principal role = (Principal) iterator.next();
roles.add(role.getName());
}
}
JBossGenericPrincipal gp = new JBossGenericPrincipal(this, subject,
authPrincipal, callerPrincipal, credential, roles, userRoles);
return gp;
}
private Principal getAuthenticatedPrincipal(Subject subject)
{
if(subject == null)
throw new IllegalArgumentException("subject is null");
Principal authPrincipal = null;
Iterator iter = subject.getPrincipals(SimplePrincipal.class).iterator();
while(iter.hasNext())
{
authPrincipal = (Principal)iter.next();
if(authPrincipal instanceof Group == false)
break;
}
return authPrincipal;
}
private GeneralizedAuthenticationManager getAuthenticationManager()
throws Exception
{
String contextID = PolicyContext.getContextID();
MBeanServer server = MBeanServerLocator.locateJBoss();
String securityDomain = (String)server.invoke(this.authenticationManagerService,
"getSecurityDomain",
new String[]{contextID}, new String[]{"java.lang.String"});
return (GeneralizedAuthenticationManager)server.invoke(this.authenticationManagerService,
"getSecurityManager",
new String[]{securityDomain}, new String[]{"java.lang.String"});
}
private AuthorizationManager getAuthorizationManager() throws Exception
{
MBeanServer server = MBeanServerLocator.locateJBoss();
GeneralizedAuthenticationManager gam = this.getAuthenticationManager();
String securityDomain = gam.getSecurityDomain();
return (AuthorizationManager)server.invoke(this.authorizationManagerService,
"getAuthorizationManager",
new String[]{securityDomain}, new String[]{"java.lang.String"});
}
}