KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > mq > security > SecurityManager


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.mq.security;
23
24 import java.security.Principal JavaDoc;
25 import java.security.acl.Group JavaDoc;
26 import java.util.Enumeration JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.Set JavaDoc;
30
31 import javax.jms.JMSException JavaDoc;
32 import javax.jms.JMSSecurityException JavaDoc;
33 import javax.management.MBeanServer JavaDoc;
34 import javax.management.MalformedObjectNameException JavaDoc;
35 import javax.management.ObjectName JavaDoc;
36 import javax.naming.Context JavaDoc;
37 import javax.naming.InitialContext JavaDoc;
38 import javax.naming.NamingException JavaDoc;
39 import javax.security.auth.Subject JavaDoc;
40
41 import org.jboss.mq.ConnectionToken;
42 import org.jboss.mq.server.JMSServerInterceptor;
43 import org.jboss.mq.server.jmx.InterceptorMBeanSupport;
44 import org.jboss.security.SimplePrincipal;
45 import org.jboss.security.SubjectSecurityManager;
46 import org.w3c.dom.Element JavaDoc;
47
48 /**
49  * A JAAS based security manager for JBossMQ.
50  *
51  * @author Peter Antman
52  * @author Scott.Stark@jboss.org
53  * @version $Revision: 37459 $
54  */

55 public class SecurityManager extends InterceptorMBeanSupport implements SecurityManagerMBean
56 {
57    /**
58     * Cached info on subject, to speed lookups.
59     */

60    class SubjectInfo
61    {
62       Subject JavaDoc subject;
63       Principal JavaDoc principal;
64       Group JavaDoc roles;
65
66       public String JavaDoc toString()
67       {
68          return "SubjectInfo {subject=" + subject + ";principal=" + principal + ";roles=" + roles.toString();
69       }
70    }
71
72    private ObjectName JavaDoc name;
73    Context JavaDoc securityCtx;
74    HashMap JavaDoc authCache = new HashMap JavaDoc(32);
75    HashMap JavaDoc securityConf = new HashMap JavaDoc(32);
76    ServerSecurityInterceptor interceptor;
77    SubjectSecurityManager sec;
78    SessionIDGenerator idGenerator;
79    Element JavaDoc defaultSecurityConfig;
80    String JavaDoc securityDomain;
81
82    protected ObjectName JavaDoc getObjectName(MBeanServer JavaDoc server, ObjectName JavaDoc name) throws MalformedObjectNameException JavaDoc
83    {
84
85       this.name = name == null ? OBJECT_NAME : name;
86
87       return this.name;
88    }
89
90    public JMSServerInterceptor getInvoker()
91    {
92       return interceptor;
93    }
94
95    public Element JavaDoc getDefaultSecurityConfig()
96    {
97       return defaultSecurityConfig;
98    }
99
100    public void setDefaultSecurityConfig(Element JavaDoc conf) throws Exception JavaDoc
101    {
102       defaultSecurityConfig = conf;
103       // Force a parse
104
new SecurityMetadata(conf);
105    }
106
107    public String JavaDoc getSecurityDomain()
108    {
109       return securityDomain;
110    }
111
112    public void setSecurityDomain(String JavaDoc securityDomain)
113    {
114       this.securityDomain = securityDomain;
115    }
116
117    // DEBUGGING METHOD: DANGEROUS
118
public String JavaDoc printAuthCache()
119    {
120       return authCache.toString();
121    }
122
123    public void addDestination(String JavaDoc destName, Element JavaDoc conf) throws Exception JavaDoc
124    {
125       SecurityMetadata m = new SecurityMetadata(conf);
126       securityConf.put(destName, m);
127    }
128
129    public void addDestination(String JavaDoc destName, String JavaDoc conf) throws Exception JavaDoc
130    {
131       SecurityMetadata m = new SecurityMetadata(conf);
132       securityConf.put(destName, m);
133    }
134
135    public void removeDestination(String JavaDoc destName) throws Exception JavaDoc
136    {
137       securityConf.remove(destName);
138    }
139
140    public SecurityMetadata getSecurityMetadata(String JavaDoc destName)
141    {
142       SecurityMetadata m = (SecurityMetadata) securityConf.get(destName);
143       if (m == null)
144       {
145          // No SecurityManager was configured for the dest,
146
// Apply the default
147
if (defaultSecurityConfig != null)
148          {
149             log.debug("No SecurityMetadadata was available for " + destName + " using default security config");
150             try
151             {
152                m = new SecurityMetadata(defaultSecurityConfig);
153             }
154             catch (Exception JavaDoc e)
155             {
156                log.warn("Unable to apply default security for destName, using guest " + destName, e);
157                m = new SecurityMetadata();
158             }
159          }
160          else
161          {
162             // default to guest
163
log.warn("No SecurityMetadadata was available for " + destName + " adding guest");
164             m = new SecurityMetadata();
165          }
166          securityConf.put(destName, m);
167       }
168       return m;
169    }
170
171    public void startService() throws Exception JavaDoc
172    {
173       // Get the JBoss security manager from JNDI
174
InitialContext JavaDoc iniCtx = new InitialContext JavaDoc();
175       try
176       {
177          sec = (SubjectSecurityManager) iniCtx.lookup(securityDomain);
178       }
179       catch (NamingException JavaDoc e)
180       {
181          // Apparently there is no security context, try adding java:/jaas
182
log.debug("Failed to lookup securityDomain=" + securityDomain, e);
183          if (securityDomain.startsWith("java:/jaas/") == false)
184             sec = (SubjectSecurityManager) iniCtx.lookup("java:/jaas/" + securityDomain);
185          else
186             throw e;
187       }
188       interceptor = new ServerSecurityInterceptor(this);
189
190       idGenerator = new SessionIDGenerator();
191
192       super.startService();
193    }
194
195    public void stopService() throws Exception JavaDoc
196    {
197       // Anything to do here?
198
}
199
200    public String JavaDoc authenticate(String JavaDoc user, String JavaDoc password) throws JMSException JavaDoc
201    {
202       /*
203       try {
204          o = securityCtx.lookup("securityMgr");
205       }catch(NamingException ex) {
206          throw new JMSException("Could not get a security context");
207       }
208       */

209       boolean trace = log.isTraceEnabled();
210       SimplePrincipal principal = new SimplePrincipal(user);
211       char[] passwordChars = null;
212       if (password != null)
213          passwordChars = password.toCharArray();
214       Subject JavaDoc subject = new Subject JavaDoc();
215       if (sec.isValid(principal, passwordChars, subject))
216       {
217          if (trace)
218             log.trace("Username: " + user + " is authenticated");
219
220          String JavaDoc sessionId = generateId(subject);
221          addId(sessionId, subject, principal);
222
223          // Should we log it out since we do not use manager any more?
224
return sessionId;
225       }
226       else
227       {
228          if (trace)
229             log.trace("User: " + user + " is NOT authenticated");
230          throw new JMSSecurityException JavaDoc("User: " + user + " is NOT authenticated");
231       }
232    }
233
234    public boolean authorize(ConnectionToken token, Set JavaDoc rolePrincipals) throws JMSException JavaDoc
235    {
236       //Unfortunately we can not reliably use the securityManager and its
237
// subject, since can not guarantee that every connection is
238
// connected to a unique thread.
239
// For now we implement the RealmMapping our self
240
boolean trace = log.isTraceEnabled();
241       boolean hasRole = false;
242
243       SubjectInfo info = (SubjectInfo) authCache.get(token.getSessionId());
244       if (info == null)
245          throw new JMSSecurityException JavaDoc("User session is not valid");
246
247       if (trace)
248          log.trace(
249             "Checking authorize on subjectInfo: "
250                + info.toString()
251                + " for rolePrincipals "
252                + rolePrincipals.toString());
253
254       Group JavaDoc group = info.roles;
255       if (group != null)
256       {
257          Iterator JavaDoc iter = rolePrincipals.iterator();
258          while (hasRole == false && iter.hasNext())
259          {
260             Principal JavaDoc role = (Principal JavaDoc) iter.next();
261             hasRole = group.isMember(role);
262          }
263
264       }
265       return hasRole;
266    }
267
268    // Is this a security problem? May a bad user set this manually and log out other users?
269
public void logout(ConnectionToken token)
270    {
271       if (token == null)
272          return;
273       // Not much we can do
274
// FIXME - how do we clear the thread local in security manager?
275
removeId(token.getSessionId());
276    }
277
278    private void addId(String JavaDoc id, Subject JavaDoc subject, Principal JavaDoc callerPrincipal)
279    {
280       boolean trace = log.isTraceEnabled();
281
282       SubjectInfo info = new SubjectInfo();
283       info.subject = subject;
284       info.principal = callerPrincipal;
285
286       Set JavaDoc subjectGroups = subject.getPrincipals(Group JavaDoc.class);
287       Iterator JavaDoc iter = subjectGroups.iterator();
288       while (iter.hasNext())
289       {
290          Group JavaDoc grp = (Group JavaDoc) iter.next();
291          String JavaDoc name = grp.getName();
292          if (name.equals("CallerPrincipal"))
293          {
294             Enumeration JavaDoc members = grp.members();
295             if (members.hasMoreElements())
296                info.principal = (Principal JavaDoc) members.nextElement();
297          }
298          else if (name.equals("Roles"))
299          {
300             if (trace)
301                log.trace("Adding group : " + grp.getClass() + " " + grp.toString());
302             info.roles = grp;
303          }
304       }
305       /* Handle null principals with no callerPrincipal. This is an indication
306          of an user that has not provided any authentication info, but
307          has been authenticated by the domain login module stack. Here we look
308          for the first non-Group Principal and use that.
309       */

310       if (callerPrincipal == null && info.principal == null)
311       {
312          Set JavaDoc subjectPrincipals = subject.getPrincipals(Principal JavaDoc.class);
313          iter = subjectPrincipals.iterator();
314          while (iter.hasNext())
315          {
316             Principal JavaDoc p = (Principal JavaDoc) iter.next();
317             if ((p instanceof Group JavaDoc) == false)
318                info.principal = p;
319          }
320       }
321
322       synchronized (authCache)
323       {
324          authCache.put(id, info);
325       }
326    }
327
328    private void removeId(String JavaDoc id)
329    {
330       synchronized (authCache)
331       {
332          authCache.remove(id);
333       }
334    }
335
336    private String JavaDoc generateId(Subject JavaDoc subject) throws JMSException JavaDoc
337    {
338       try
339       {
340          return idGenerator.nextSessionId();
341       }
342       catch (Exception JavaDoc ex)
343       {
344          log.error("Could not generate a secure sessionID", ex);
345          //Dont show client the real reason
346
throw new JMSSecurityException JavaDoc("Could not generate a secure sessionID");
347       }
348    }
349
350    /**
351     * @see InterceptorMBean#getInterceptor()
352     */

353    public JMSServerInterceptor getInterceptor()
354    {
355       return interceptor;
356    }
357
358 } // SecurityManager
359
Popular Tags