    001    /*
    002     * Copyright 2009 Red Hat, Inc.
    003     * Red Hat licenses this file to you under the Apache License, version
    004     * 2.0 (the "License"); you may not use this file except in compliance
    005     * with the License.  You may obtain a copy of the License at
    006     *    http://www.apache.org/licenses/LICENSE-2.0
    007     * Unless required by applicable law or agreed to in writing, software
    008     * distributed under the License is distributed on an "AS IS" BASIS,
    009     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    010     * implied.  See the License for the specific language governing
    011     * permissions and limitations under the License.
    012     */
    013
    014    package org.hornetq.spi.core.security;
    015
    016    import java.security.Principal;
    017    import java.security.acl.Group;
    018    import java.util.HashSet;
    019    import java.util.Iterator;
    020    import java.util.Set;
    021
    022    import javax.security.auth.Subject;
    023    import javax.security.auth.callback.CallbackHandler;
    024    import javax.security.auth.login.Configuration;
    025    import javax.security.auth.login.LoginContext;
    026    import javax.security.auth.login.LoginException;
    027
    028    import org.hornetq.core.logging.Logger;
    029    import org.hornetq.core.security.CheckType;
    030    import org.hornetq.core.security.Role;
    031    import org.hornetq.core.server.HornetQComponent;
    032
    033    /**
    034     * This implementation delegates to the JAAS security interfaces.
    035     *
    036     * The {@link Subject} returned by the login context is expecting to have a {@link Group} with the <code>Roles</code> name
    037     * containing a set of {@link Principal} for each role of the user.
    038     *
    039     * @author <a href="ataylor@redhat.com">Andy Taylor</a>
    040     * @author <a href="tim.fox@jboss.com">Tim Fox</a>
    041     * @author <a href="jmesnil@redhat.com">Jeff Mesnil</a>
    042     */
    043    public class JAASSecurityManager implements HornetQSecurityManager, HornetQComponent
    044    {
    045       private static final Logger log = Logger.getLogger(JAASSecurityManager.class);
    046
    047       // Static --------------------------------------------------------
    048
    049       // Attributes ----------------------------------------------------
    050
    051       private final boolean trace = JAASSecurityManager.log.isTraceEnabled();
    052
    053       private String configurationName;
    054
    055       private boolean started;
    056
    057       private CallbackHandler callbackHandler;
    058
    059       private Configuration config;
    060
    061       // HornetQSecurityManager implementation -----------------------------
    062
    063       public boolean validateUser(final String user, final String password)
    064       {
    065          try
    066          {
    067             getAuthenticatedSubject(user, password);
    068             return true;
    069          }
    070          catch (LoginException e1)
    071          {
    072             return false;
    073          }
    074       }
    075
    076       public boolean validateUserAndRole(final String user,
    077                                          final String password,
    078                                          final Set<Role> roles,
    079                                          final CheckType checkType)
    080       {
    081          Subject localSubject = null;
    082          try
    083          {
    084             localSubject = getAuthenticatedSubject(user, password);
    085          }
    086          catch (LoginException e1)
    087          {
    088             return false;
    089          }
    090
    091          boolean authenticated = true;
    092
    093          if (localSubject != null)
    094          {
    095             Set<Principal> rolePrincipals = getRolePrincipals(checkType, roles);
    096
    097             // authenticated = realmMapping.doesUserHaveRole(principal, rolePrincipals);
    098
    099             boolean hasRole = false;
    100             // check that the caller is authenticated to the current thread
    101
    102             // Check the caller's roles
    103             Group subjectRoles = getSubjectRoles(localSubject);
    104             if (subjectRoles != null)
    105             {
    106                Iterator<Principal> iter = rolePrincipals.iterator();
    107                while (!hasRole && iter.hasNext())
    108                {
    109                   Principal role = iter.next();
    110                   hasRole = subjectRoles.isMember(role);
    111                }
    112             }
    113
    114             authenticated = hasRole;
    115
    116             if (trace)
    117             {
    118                JAASSecurityManager.log.trace("user " + user + (authenticated ? " is " : " is NOT ") + "authorized");
    119             }
    120          }
    121          return authenticated;
    122       }
    123
    124       public void addRole(final String user, final String role)
    125       {
    126          // NO-OP
    127       }
    128
    129       public void addUser(final String user, final String password)
    130       {
    131          // NO-OP
    132       }
    133
    134       public void removeRole(final String user, final String role)
    135       {
    136          // NO-OP
    137       }
    138
    139       public void removeUser(final String user)
    140       {
    141          // NO-OP
    142       }
    143
    144       public void setDefaultUser(final String username)
    145       {
    146          // NO-OP
    147       }
    148
    149       // HornetQComponent implementation -----------------------------
    150
    151       /**
    152        * lifecycle method, needs to be called
    153        *
    154        * @throws Exception
    155        */
    156       public synchronized void start() throws Exception
    157       {
    158          if (started)
    159          {
    160             return;
    161          }
    162
    163          started = true;
    164       }
    165
    166       public synchronized void stop()
    167       {
    168          if (!started)
    169          {
    170             return;
    171          }
    172          started = false;
    173       }
    174
    175       public synchronized boolean isStarted()
    176       {
    177          return started;
    178       }
    179
    180       private Subject getAuthenticatedSubject(final String user, final String password) throws LoginException
    181       {
    182          SimplePrincipal principal = user == null ? null : new SimplePrincipal(user);
    183
    184          char[] passwordChars = null;
    185
    186          if (password != null)
    187          {
    188             passwordChars = password.toCharArray();
    189          }
    190
    191          Subject subject = new Subject();
    192
    193          if (user != null)
    194          {
    195             subject.getPrincipals().add(principal);
    196          }
    197          subject.getPrivateCredentials().add(passwordChars);
    198
    199          LoginContext lc = new LoginContext(configurationName, subject, callbackHandler, config);
    200          lc.login();
    201          return lc.getSubject();
    202       }
    203
    204       private Group getSubjectRoles(final Subject subject)
    205       {
    206          Set<Group> subjectGroups = subject.getPrincipals(Group.class);
    207          Iterator<Group> iter = subjectGroups.iterator();
    208          Group roles = null;
    209          while (iter.hasNext())
    210          {
    211             Group grp = iter.next();
    212             String name = grp.getName();
    213             if (name.equals("Roles"))
    214             {
    215                roles = grp;
    216             }
    217          }
    218          return roles;
    219       }
    220
    221       private Set<Principal> getRolePrincipals(final CheckType checkType, final Set<Role> roles)
    222       {
    223          Set<Principal> principals = new HashSet<Principal>();
    224          for (Role role : roles)
    225          {
    226             if (checkType.hasRole(role))
    227             {
    228                principals.add(new SimplePrincipal(role.getName()));
    229             }
    230          }
    231          return principals;
    232       }
    233
    234       // Public --------------------------------------------------------
    235
    236       public void setConfigurationName(final String configurationName)
    237       {
    238          this.configurationName = configurationName;
    239       }
    240
    241       public void setCallbackHandler(final CallbackHandler handler)
    242       {
    243          callbackHandler = handler;
    244       }
    245
    246       public void setConfiguration(final Configuration config)
    247       {
    248          this.config = config;
    249       }
    250
    251       // Private -------------------------------------------------------
    252
    253       // Inner classes -------------------------------------------------
    254
    255       public static class SimplePrincipal implements Principal, java.io.Serializable
    256       {
    257          private static final long serialVersionUID = 1L;
    258
    259          private final String name;
    260
    261          public SimplePrincipal(final String name)
    262          {
    263             this.name = name;
    264          }
    265
    266          /** Compare this SimplePrincipal's name against another Principal
    267          @return true if name equals another.getName();
    268           */
    269          @Override
    270          public boolean equals(final Object another)
    271          {
    272             if (!(another instanceof Principal))
    273             {
    274                return false;
    275             }
    276             String anotherName = ((Principal)another).getName();
    277             boolean equals = false;
    278             if (name == null)
    279             {
    280                equals = anotherName == null;
    281             }
    282             else
    283             {
    284                equals = name.equals(anotherName);
    285             }
    286             return equals;
    287          }
    288
    289          @Override
    290          public int hashCode()
    291          {
    292             return name == null ? 0 : name.hashCode();
    293          }
    294
    295          @Override
    296          public String toString()
    297          {
    298             return name;
    299          }
    300
    301          public String getName()
    302          {
    303             return name;
    304          }
    305       }
    306
    307    }