diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/PropertyUserStore.java b/jetty-security/src/main/java/org/eclipse/jetty/security/PropertyUserStore.java index 604dbacef4f..43b58603ea2 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/PropertyUserStore.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/PropertyUserStore.java @@ -18,12 +18,19 @@ package org.eclipse.jetty.security; +import org.eclipse.jetty.util.PathWatcher; +import org.eclipse.jetty.util.PathWatcher.PathWatchEvent; +import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.PathResource; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.util.security.Credential; + import java.io.File; import java.io.IOException; import java.nio.file.Path; -import java.security.Principal; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -31,20 +38,6 @@ import java.util.Map; import java.util.Properties; import java.util.Set; -import javax.security.auth.Subject; - - -import org.eclipse.jetty.server.UserIdentity; -import org.eclipse.jetty.util.PathWatcher; -import org.eclipse.jetty.util.PathWatcher.PathWatchEvent; -import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.component.AbstractLifeCycle; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.resource.PathResource; -import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.util.security.Credential; - /** * PropertyUserStore *

@@ -59,7 +52,7 @@ import org.eclipse.jetty.util.security.Credential; * * If DIGEST Authentication is used, the password must be in a recoverable format, either plain text or OBF:. */ -public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.Listener +public class PropertyUserStore extends UserStore implements PathWatcher.Listener { private static final Logger LOG = Log.getLogger(PropertyUserStore.class); @@ -69,10 +62,7 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher. protected PathWatcher pathWatcher; protected boolean hotReload = false; // default is not to reload - protected IdentityService _identityService = new DefaultIdentityService(); protected boolean _firstLoad = true; // true if first load, false from that point on - protected final List _knownUsers = new ArrayList(); - protected final Map _knownUserIdentities = new HashMap(); protected List _listeners; /** @@ -145,12 +135,6 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher. { _configPath = configPath; } - - /* ------------------------------------------------------------ */ - public UserIdentity getUserIdentity(String userName) - { - return _knownUserIdentities.get(userName); - } /* ------------------------------------------------------------ */ /** @@ -199,8 +183,8 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher. StringBuilder s = new StringBuilder(); s.append(this.getClass().getName()); s.append("["); - s.append("users.count=").append(this._knownUsers.size()); - s.append("identityService=").append(this._identityService); + s.append("users.count=").append(this.getKnownUserIdentities().size()); + s.append("identityService=").append(this.getIdentityService()); s.append("]"); return s.toString(); } @@ -220,7 +204,7 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher. if (getConfigResource().exists()) properties.load(getConfigResource().getInputStream()); - Set known = new HashSet(); + Set known = new HashSet<>(); for (Map.Entry entry : properties.entrySet()) { @@ -243,27 +227,12 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher. } known.add(username); Credential credential = Credential.getCredential(credentials); - - Principal userPrincipal = new AbstractLoginService.UserPrincipal(username,credential); - Subject subject = new Subject(); - subject.getPrincipals().add(userPrincipal); - subject.getPrivateCredentials().add(credential); - - if (roles != null) - { - for (String role : roleArray) - { - subject.getPrincipals().add(new AbstractLoginService.RolePrincipal(role)); - } - } - - subject.setReadOnly(); - - _knownUserIdentities.put(username,_identityService.newUserIdentity(subject,userPrincipal,roleArray)); + addUser( username, credential, roleArray ); notifyUpdate(username,credential,roleArray); } } + final List _knownUsers = new ArrayList(); synchronized (_knownUsers) { /* @@ -277,7 +246,7 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher. String user = users.next(); if (!known.contains(user)) { - _knownUserIdentities.remove(user); + removeUser( user ); notifyRemove(user); } } diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/UserStore.java b/jetty-security/src/main/java/org/eclipse/jetty/security/UserStore.java new file mode 100644 index 00000000000..d23a17e9692 --- /dev/null +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/UserStore.java @@ -0,0 +1,76 @@ +// +// ======================================================================== +// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.security; + +import org.eclipse.jetty.server.UserIdentity; +import org.eclipse.jetty.util.component.AbstractLifeCycle; +import org.eclipse.jetty.util.security.Credential; + +import javax.security.auth.Subject; +import java.security.Principal; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Base class to store User + */ +public class UserStore extends AbstractLifeCycle +{ + private IdentityService _identityService = new DefaultIdentityService(); + private final Map _knownUserIdentities = new ConcurrentHashMap<>(); + + protected void addUser( String username, Credential credential, String[] roles) + { + Principal userPrincipal = new AbstractLoginService.UserPrincipal( username, credential); + Subject subject = new Subject(); + subject.getPrincipals().add(userPrincipal); + subject.getPrivateCredentials().add(credential); + + if (roles != null) + { + for (String role : roles) + { + subject.getPrincipals().add(new AbstractLoginService.RolePrincipal(role)); + } + } + + subject.setReadOnly(); + _knownUserIdentities.put(username,_identityService.newUserIdentity(subject,userPrincipal,roles)); + } + + protected void removeUser(String username) + { + _knownUserIdentities.remove(username); + } + + public UserIdentity getUserIdentity(String userName) + { + return _knownUserIdentities.get(userName); + } + + public IdentityService getIdentityService() + { + return _identityService; + } + + protected Map getKnownUserIdentities() + { + return _knownUserIdentities; + } +} diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/TestLoginService.java b/jetty-security/src/test/java/org/eclipse/jetty/security/TestLoginService.java index e8adc097cf8..a977e9bdd31 100644 --- a/jetty-security/src/test/java/org/eclipse/jetty/security/TestLoginService.java +++ b/jetty-security/src/test/java/org/eclipse/jetty/security/TestLoginService.java @@ -19,9 +19,14 @@ package org.eclipse.jetty.security; +import java.security.Principal; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Set; +import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.util.security.Credential; /** @@ -31,9 +36,8 @@ import org.eclipse.jetty.util.security.Credential; */ public class TestLoginService extends AbstractLoginService { - protected Map _users = new HashMap<>(); - protected Map _roles = new HashMap<>(); - + + UserStore userStore = new UserStore(); public TestLoginService(String name) @@ -43,9 +47,7 @@ public class TestLoginService extends AbstractLoginService public void putUser (String username, Credential credential, String[] roles) { - UserPrincipal userPrincipal = new UserPrincipal(username,credential); - _users.put(username, userPrincipal); - _roles.put(username, roles); + userStore.addUser( username, credential, roles ); } /** @@ -54,7 +56,16 @@ public class TestLoginService extends AbstractLoginService @Override protected String[] loadRoleInfo(UserPrincipal user) { - return _roles.get(user.getName()); + UserIdentity userIdentity = userStore.getUserIdentity( user.getName() ); + Set roles = userIdentity.getSubject().getPrincipals( RolePrincipal.class); + if (roles == null) + return null; + + List list = new ArrayList<>(); + for (RolePrincipal r:roles) + list.add(r.getName()); + + return list.toArray(new String[roles.size()]); } /** @@ -63,7 +74,8 @@ public class TestLoginService extends AbstractLoginService @Override protected UserPrincipal loadUserInfo(String username) { - return _users.get(username); + UserIdentity userIdentity = userStore.getUserIdentity( username ); + return userIdentity == null ? null : (UserPrincipal) userIdentity.getUserPrincipal(); } } diff --git a/pom.xml b/pom.xml index baf709ed44f..f593767451d 100644 --- a/pom.xml +++ b/pom.xml @@ -581,7 +581,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.19.1 + 2.20 @{argLine} -Dfile.encoding=UTF-8 -Duser.language=en -Duser.region=US -showversion -Xmx1g -Xms1g -XX:+PrintGCDetails false