1// 2// ======================================================================== 3// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 4// ------------------------------------------------------------------------ 5// All rights reserved. This program and the accompanying materials 6// are made available under the terms of the Eclipse Public License v1.0 7// and Apache License v2.0 which accompanies this distribution. 8// 9// The Eclipse Public License is available at 10// http://www.eclipse.org/legal/epl-v10.html 11// 12// The Apache License v2.0 is available at 13// http://www.opensource.org/licenses/apache2.0.php 14// 15// You may elect to redistribute this code under either of these licenses. 16// ======================================================================== 17// 18 19 20package org.eclipse.jetty.security; 21 22import java.io.IOException; 23import java.io.Serializable; 24import java.security.Principal; 25import java.util.Map; 26import java.util.concurrent.ConcurrentHashMap; 27import java.util.concurrent.ConcurrentMap; 28 29import javax.security.auth.Subject; 30 31import org.eclipse.jetty.server.UserIdentity; 32import org.eclipse.jetty.util.component.AbstractLifeCycle; 33import org.eclipse.jetty.util.log.Log; 34import org.eclipse.jetty.util.log.Logger; 35import org.eclipse.jetty.util.security.Credential; 36 37 38 39/* ------------------------------------------------------------ */ 40/** 41 * A login service that keeps UserIdentities in a concurrent map 42 * either as the source or a cache of the users. 43 * 44 */ 45public abstract class MappedLoginService extends AbstractLifeCycle implements LoginService 46{ 47 private static final Logger LOG = Log.getLogger(MappedLoginService.class); 48 49 protected IdentityService _identityService=new DefaultIdentityService(); 50 protected String _name; 51 protected final ConcurrentMap<String, UserIdentity> _users=new ConcurrentHashMap<String, UserIdentity>(); 52 53 /* ------------------------------------------------------------ */ 54 protected MappedLoginService() 55 { 56 } 57 58 /* ------------------------------------------------------------ */ 59 /** Get the name. 60 * @return the name 61 */ 62 public String getName() 63 { 64 return _name; 65 } 66 67 /* ------------------------------------------------------------ */ 68 /** Get the identityService. 69 * @return the identityService 70 */ 71 public IdentityService getIdentityService() 72 { 73 return _identityService; 74 } 75 76 /* ------------------------------------------------------------ */ 77 /** Get the users. 78 * @return the users 79 */ 80 public ConcurrentMap<String, UserIdentity> getUsers() 81 { 82 return _users; 83 } 84 85 /* ------------------------------------------------------------ */ 86 /** Set the identityService. 87 * @param identityService the identityService to set 88 */ 89 public void setIdentityService(IdentityService identityService) 90 { 91 if (isRunning()) 92 throw new IllegalStateException("Running"); 93 _identityService = identityService; 94 } 95 96 /* ------------------------------------------------------------ */ 97 /** Set the name. 98 * @param name the name to set 99 */ 100 public void setName(String name) 101 { 102 if (isRunning()) 103 throw new IllegalStateException("Running"); 104 _name = name; 105 } 106 107 /* ------------------------------------------------------------ */ 108 /** Set the users. 109 * @param users the users to set 110 */ 111 public void setUsers(Map<String, UserIdentity> users) 112 { 113 if (isRunning()) 114 throw new IllegalStateException("Running"); 115 _users.clear(); 116 _users.putAll(users); 117 } 118 119 /* ------------------------------------------------------------ */ 120 /** 121 * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart() 122 */ 123 @Override 124 protected void doStart() throws Exception 125 { 126 loadUsers(); 127 super.doStart(); 128 } 129 130 /* ------------------------------------------------------------ */ 131 @Override 132 protected void doStop() throws Exception 133 { 134 super.doStop(); 135 } 136 137 /* ------------------------------------------------------------ */ 138 public void logout(UserIdentity identity) 139 { 140 LOG.debug("logout {}",identity); 141 } 142 143 /* ------------------------------------------------------------ */ 144 @Override 145 public String toString() 146 { 147 return this.getClass().getSimpleName()+"["+_name+"]"; 148 } 149 150 /* ------------------------------------------------------------ */ 151 /** Put user into realm. 152 * Called by implementations to put the user data loaded from 153 * file/db etc into the user structure. 154 * @param userName User name 155 * @param info a UserIdentity instance, or a String password or Credential instance 156 * @return User instance 157 */ 158 protected synchronized UserIdentity putUser(String userName, Object info) 159 { 160 final UserIdentity identity; 161 if (info instanceof UserIdentity) 162 identity=(UserIdentity)info; 163 else 164 { 165 Credential credential = (info instanceof Credential)?(Credential)info:Credential.getCredential(info.toString()); 166 167 Principal userPrincipal = new KnownUser(userName,credential); 168 Subject subject = new Subject(); 169 subject.getPrincipals().add(userPrincipal); 170 subject.getPrivateCredentials().add(credential); 171 subject.setReadOnly(); 172 identity=_identityService.newUserIdentity(subject,userPrincipal,IdentityService.NO_ROLES); 173 } 174 175 _users.put(userName,identity); 176 return identity; 177 } 178 179 /* ------------------------------------------------------------ */ 180 /** Put user into realm. 181 * @param userName The user to add 182 * @param credential The users Credentials 183 * @param roles The users roles 184 * @return UserIdentity 185 */ 186 public synchronized UserIdentity putUser(String userName, Credential credential, String[] roles) 187 { 188 Principal userPrincipal = new KnownUser(userName,credential); 189 Subject subject = new Subject(); 190 subject.getPrincipals().add(userPrincipal); 191 subject.getPrivateCredentials().add(credential); 192 193 if (roles!=null) 194 for (String role : roles) 195 subject.getPrincipals().add(new RolePrincipal(role)); 196 197 subject.setReadOnly(); 198 UserIdentity identity=_identityService.newUserIdentity(subject,userPrincipal,roles); 199 _users.put(userName,identity); 200 return identity; 201 } 202 203 /* ------------------------------------------------------------ */ 204 public void removeUser(String username) 205 { 206 _users.remove(username); 207 } 208 209 /* ------------------------------------------------------------ */ 210 /** 211 * @see org.eclipse.jetty.security.LoginService#login(java.lang.String, java.lang.Object) 212 */ 213 public UserIdentity login(String username, Object credentials) 214 { 215 UserIdentity user = _users.get(username); 216 217 if (user==null) 218 user = loadUser(username); 219 220 if (user!=null) 221 { 222 UserPrincipal principal = (UserPrincipal)user.getUserPrincipal(); 223 if (principal.authenticate(credentials)) 224 return user; 225 } 226 return null; 227 } 228 229 /* ------------------------------------------------------------ */ 230 public boolean validate(UserIdentity user) 231 { 232 if (_users.containsKey(user.getUserPrincipal().getName())) 233 return true; 234 235 if (loadUser(user.getUserPrincipal().getName())!=null) 236 return true; 237 238 return false; 239 } 240 241 /* ------------------------------------------------------------ */ 242 protected abstract UserIdentity loadUser(String username); 243 244 /* ------------------------------------------------------------ */ 245 protected abstract void loadUsers() throws IOException; 246 247 248 /* ------------------------------------------------------------ */ 249 /* ------------------------------------------------------------ */ 250 /* ------------------------------------------------------------ */ 251 public interface UserPrincipal extends Principal,Serializable 252 { 253 boolean authenticate(Object credentials); 254 public boolean isAuthenticated(); 255 } 256 257 /* ------------------------------------------------------------ */ 258 /* ------------------------------------------------------------ */ 259 /* ------------------------------------------------------------ */ 260 public static class RolePrincipal implements Principal,Serializable 261 { 262 private static final long serialVersionUID = 2998397924051854402L; 263 private final String _roleName; 264 public RolePrincipal(String name) 265 { 266 _roleName=name; 267 } 268 public String getName() 269 { 270 return _roleName; 271 } 272 } 273 274 /* ------------------------------------------------------------ */ 275 /* ------------------------------------------------------------ */ 276 /* ------------------------------------------------------------ */ 277 public static class Anonymous implements UserPrincipal,Serializable 278 { 279 private static final long serialVersionUID = 1097640442553284845L; 280 281 public boolean isAuthenticated() 282 { 283 return false; 284 } 285 286 public String getName() 287 { 288 return "Anonymous"; 289 } 290 291 public boolean authenticate(Object credentials) 292 { 293 return false; 294 } 295 296 } 297 298 /* ------------------------------------------------------------ */ 299 /* ------------------------------------------------------------ */ 300 /* ------------------------------------------------------------ */ 301 public static class KnownUser implements UserPrincipal,Serializable 302 { 303 private static final long serialVersionUID = -6226920753748399662L; 304 private final String _name; 305 private final Credential _credential; 306 307 /* -------------------------------------------------------- */ 308 public KnownUser(String name,Credential credential) 309 { 310 _name=name; 311 _credential=credential; 312 } 313 314 /* -------------------------------------------------------- */ 315 public boolean authenticate(Object credentials) 316 { 317 return _credential!=null && _credential.check(credentials); 318 } 319 320 /* ------------------------------------------------------------ */ 321 public String getName() 322 { 323 return _name; 324 } 325 326 /* -------------------------------------------------------- */ 327 public boolean isAuthenticated() 328 { 329 return true; 330 } 331 332 /* -------------------------------------------------------- */ 333 @Override 334 public String toString() 335 { 336 return _name; 337 } 338 } 339} 340 341