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 014package org.hornetq.spi.core.security; 015 016import java.security.Principal; 017import java.security.acl.Group; 018import java.util.HashSet; 019import java.util.Iterator; 020import java.util.Set; 021 022import javax.security.auth.Subject; 023import javax.security.auth.callback.CallbackHandler; 024import javax.security.auth.login.Configuration; 025import javax.security.auth.login.LoginContext; 026import javax.security.auth.login.LoginException; 027 028import org.hornetq.core.logging.Logger; 029import org.hornetq.core.security.CheckType; 030import org.hornetq.core.security.Role; 031import 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 */ 043public 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}