package org.jboss.mq.security;
import java.security.Principal;
import java.security.acl.Group;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import javax.jms.JMSException;
import javax.jms.JMSSecurityException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.security.auth.Subject;
import org.jboss.mq.ConnectionToken;
import org.jboss.mq.server.JMSServerInterceptor;
import org.jboss.mq.server.jmx.InterceptorMBeanSupport;
import org.jboss.security.SimplePrincipal;
import org.jboss.security.SubjectSecurityManager;
import org.w3c.dom.Element;
public class SecurityManager extends InterceptorMBeanSupport implements SecurityManagerMBean
{
class SubjectInfo
{
Subject subject;
Principal principal;
Group roles;
public String toString()
{
return "SubjectInfo {subject=" + subject + ";principal=" + principal + ";roles=" + roles.toString();
}
}
private ObjectName name;
Context securityCtx;
HashMap authCache = new HashMap(32);
HashMap securityConf = new HashMap(32);
ServerSecurityInterceptor interceptor;
SubjectSecurityManager sec;
SessionIDGenerator idGenerator;
Element defaultSecurityConfig;
String securityDomain;
protected ObjectName getObjectName(MBeanServer server, ObjectName name) throws MalformedObjectNameException
{
this.name = name == null ? OBJECT_NAME : name;
return this.name;
}
public JMSServerInterceptor getInvoker()
{
return interceptor;
}
public Element getDefaultSecurityConfig()
{
return defaultSecurityConfig;
}
public void setDefaultSecurityConfig(Element conf) throws Exception
{
defaultSecurityConfig = conf;
new SecurityMetadata(conf);
}
public String getSecurityDomain()
{
return securityDomain;
}
public void setSecurityDomain(String securityDomain)
{
this.securityDomain = securityDomain;
}
public String printAuthCache()
{
return authCache.toString();
}
public void addDestination(String destName, Element conf) throws Exception
{
SecurityMetadata m = new SecurityMetadata(conf);
securityConf.put(destName, m);
}
public void addDestination(String destName, String conf) throws Exception
{
SecurityMetadata m = new SecurityMetadata(conf);
securityConf.put(destName, m);
}
public void removeDestination(String destName) throws Exception
{
securityConf.remove(destName);
}
public SecurityMetadata getSecurityMetadata(String destName)
{
SecurityMetadata m = (SecurityMetadata) securityConf.get(destName);
if (m == null)
{
if (defaultSecurityConfig != null)
{
log.debug("No SecurityMetadadata was available for " + destName + " using default security config");
try
{
m = new SecurityMetadata(defaultSecurityConfig);
}
catch (Exception e)
{
log.warn("Unable to apply default security for destName, using guest " + destName, e);
m = new SecurityMetadata();
}
}
else
{
log.warn("No SecurityMetadadata was available for " + destName + " adding guest");
m = new SecurityMetadata();
}
securityConf.put(destName, m);
}
return m;
}
public void startService() throws Exception
{
InitialContext iniCtx = new InitialContext();
try
{
sec = (SubjectSecurityManager) iniCtx.lookup(securityDomain);
}
catch (NamingException e)
{
log.debug("Failed to lookup securityDomain=" + securityDomain, e);
if (securityDomain.startsWith("java:/jaas/") == false)
sec = (SubjectSecurityManager) iniCtx.lookup("java:/jaas/" + securityDomain);
else
throw e;
}
interceptor = new ServerSecurityInterceptor(this);
idGenerator = new SessionIDGenerator();
super.startService();
}
public void stopService() throws Exception
{
}
public String authenticate(String user, String password) throws JMSException
{
boolean trace = log.isTraceEnabled();
SimplePrincipal principal = new SimplePrincipal(user);
char[] passwordChars = null;
if (password != null)
passwordChars = password.toCharArray();
Subject subject = new Subject();
if (sec.isValid(principal, passwordChars, subject))
{
if (trace)
log.trace("Username: " + user + " is authenticated");
String sessionId = generateId(subject);
addId(sessionId, subject, principal);
return sessionId;
}
else
{
if (trace)
log.trace("User: " + user + " is NOT authenticated");
throw new JMSSecurityException("User: " + user + " is NOT authenticated");
}
}
public boolean authorize(ConnectionToken token, Set rolePrincipals) throws JMSException
{
boolean trace = log.isTraceEnabled();
boolean hasRole = false;
SubjectInfo info = (SubjectInfo) authCache.get(token.getSessionId());
if (info == null)
throw new JMSSecurityException("User session is not valid");
if (trace)
log.trace(
"Checking authorize on subjectInfo: "
+ info.toString()
+ " for rolePrincipals "
+ rolePrincipals.toString());
Group group = info.roles;
if (group != null)
{
Iterator iter = rolePrincipals.iterator();
while (hasRole == false && iter.hasNext())
{
Principal role = (Principal) iter.next();
hasRole = group.isMember(role);
}
}
return hasRole;
}
public void logout(ConnectionToken token)
{
if (token == null)
return;
removeId(token.getSessionId());
}
private void addId(String id, Subject subject, Principal callerPrincipal)
{
boolean trace = log.isTraceEnabled();
SubjectInfo info = new SubjectInfo();
info.subject = subject;
info.principal = callerPrincipal;
Set subjectGroups = subject.getPrincipals(Group.class);
Iterator iter = subjectGroups.iterator();
while (iter.hasNext())
{
Group grp = (Group) iter.next();
String name = grp.getName();
if (name.equals("CallerPrincipal"))
{
Enumeration members = grp.members();
if (members.hasMoreElements())
info.principal = (Principal) members.nextElement();
}
else if (name.equals("Roles"))
{
if (trace)
log.trace("Adding group : " + grp.getClass() + " " + grp.toString());
info.roles = grp;
}
}
if (callerPrincipal == null && info.principal == null)
{
Set subjectPrincipals = subject.getPrincipals(Principal.class);
iter = subjectPrincipals.iterator();
while (iter.hasNext())
{
Principal p = (Principal) iter.next();
if ((p instanceof Group) == false)
info.principal = p;
}
}
synchronized (authCache)
{
authCache.put(id, info);
}
}
private void removeId(String id)
{
synchronized (authCache)
{
authCache.remove(id);
}
}
private String generateId(Subject subject) throws JMSException
{
try
{
return idGenerator.nextSessionId();
}
catch (Exception ex)
{
log.error("Could not generate a secure sessionID", ex);
throw new JMSSecurityException("Could not generate a secure sessionID");
}
}
public JMSServerInterceptor getInterceptor()
{
return interceptor;
}
}