From 1e30a58419ef1b1f156be6f6d0158e7bd1622149 Mon Sep 17 00:00:00 2001 From: Thomas Becker Date: Fri, 26 Aug 2011 19:34:37 +0200 Subject: [PATCH 01/12] HashLoginService code format --- .../jetty/security/HashLoginService.java | 62 +++++++++---------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java index 5e5a8445863..0d6a7e45b7b 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java @@ -36,22 +36,18 @@ import org.eclipse.jetty.util.resource.Resource; /** * Properties User Realm. * - * An implementation of UserRealm that stores users and roles in-memory in - * HashMaps. + * An implementation of UserRealm that stores users and roles in-memory in HashMaps. *

- * Typically these maps are populated by calling the load() method or passing a - * properties resource to the constructor. The format of the properties file is: + * Typically these maps are populated by calling the load() method or passing a properties resource to the constructor. The format of the properties file is: * *

  *  username: password [,rolename ...]
  * 
* - * Passwords may be clear text, obfuscated or checksummed. The class - * com.eclipse.Util.Password should be used to generate obfuscated passwords or - * password checksums. + * Passwords may be clear text, obfuscated or checksummed. The class com.eclipse.Util.Password should be used to generate obfuscated passwords or password + * checksums. * - * If DIGEST Authentication is used, the password must be in a recoverable - * format, either plain text or OBF:. + * If DIGEST Authentication is used, the password must be in a recoverable format, either plain text or OBF:. */ public class HashLoginService extends MappedLoginService { @@ -72,14 +68,14 @@ public class HashLoginService extends MappedLoginService { setName(name); } - + /* ------------------------------------------------------------ */ public HashLoginService(String name, String config) { setName(name); setConfig(config); } - + /* ------------------------------------------------------------ */ public String getConfig() { @@ -89,7 +85,7 @@ public class HashLoginService extends MappedLoginService /* ------------------------------------------------------------ */ public void getConfig(String config) { - _config=config; + _config = config; } /* ------------------------------------------------------------ */ @@ -100,11 +96,10 @@ public class HashLoginService extends MappedLoginService /* ------------------------------------------------------------ */ /** - * Load realm users from properties file. The property file maps usernames - * to password specs followed by an optional comma separated list of role - * names. + * Load realm users from properties file. The property file maps usernames to password specs followed by an optional comma separated list of role names. * - * @param config Filename or url of user properties file. + * @param config + * Filename or url of user properties file. */ public void setConfig(String config) { @@ -129,30 +124,31 @@ public class HashLoginService extends MappedLoginService { return null; } - + /* ------------------------------------------------------------ */ @Override public void loadUsers() throws IOException { - if (_config==null) + if (_config == null) return; _configResource = Resource.newResource(_config); if (LOG.isDebugEnabled()) LOG.debug("Load " + this + " from " + _config); + Properties properties = new Properties(); properties.load(_configResource.getInputStream()); Set known = new HashSet(); for (Map.Entry entry : properties.entrySet()) { - String username = ((String) entry.getKey()).trim(); - String credentials = ((String) entry.getValue()).trim(); + String username = ((String)entry.getKey()).trim(); + String credentials = ((String)entry.getValue()).trim(); String roles = null; int c = credentials.indexOf(','); if (c > 0) { roles = credentials.substring(c + 1).trim(); - credentials = credentials.substring(0, c).trim(); + credentials = credentials.substring(0,c).trim(); } if (username != null && username.length() > 0 && credentials != null && credentials.length() > 0) @@ -164,17 +160,16 @@ public class HashLoginService extends MappedLoginService putUser(username,Credential.getCredential(credentials),roleArray); } } - + Iterator users = _users.keySet().iterator(); - while(users.hasNext()) + while (users.hasNext()) { - String user=users.next(); + String user = users.next(); if (!known.contains(user)) users.remove(); } } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart() @@ -182,7 +177,7 @@ public class HashLoginService extends MappedLoginService protected void doStart() throws Exception { super.doStart(); - + if (getRefreshInterval() > 0) { _scanner = new Scanner(); @@ -194,10 +189,11 @@ public class HashLoginService extends MappedLoginService { public boolean accept(File dir, String name) { - File f = new File(dir, name); + File f = new File(dir,name); try { - if (f.compareTo(_configResource.getFile()) == 0) return true; + if (f.compareTo(_configResource.getFile()) == 0) + return true; } catch (IOException e) { @@ -212,8 +208,10 @@ public class HashLoginService extends MappedLoginService { public void filesChanged(List filenames) throws Exception { - if (filenames == null) return; - if (filenames.isEmpty()) return; + if (filenames == null) + return; + if (filenames.isEmpty()) + return; if (filenames.size() == 1) { Resource r = Resource.newResource(filenames.get(0)); @@ -241,9 +239,9 @@ public class HashLoginService extends MappedLoginService protected void doStop() throws Exception { super.doStop(); - if (_scanner != null) _scanner.stop(); + if (_scanner != null) + _scanner.stop(); _scanner = null; } - } From 95ee2157bddc7fe60a43591a160d49383078d64e Mon Sep 17 00:00:00 2001 From: Thomas Becker Date: Fri, 26 Aug 2011 19:35:51 +0200 Subject: [PATCH 02/12] JETTY-1414 applied to PropertyUserStore --- .../org/eclipse/jetty/security/PropertyUserStore.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 5e463165103..7f49893030d 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 @@ -201,15 +201,17 @@ public class PropertyUserStore extends AbstractLifeCycle _scanner.addListener(new BulkListener() { - public void filesChanged(List filenames) throws Exception + public void filesChanged(List filenames) throws Exception { if (filenames == null) return; if (filenames.isEmpty()) return; - if (filenames.size() == 1 && filenames.get(0).equals(getConfigResource().getFile().getAbsolutePath())) + if (filenames.size() == 1) { - loadUsers(); + Resource r = Resource.newResource(filenames.get(0)); + if (r.getFile().equals(_configResource.getFile())) + loadUsers(); } } From 129a66f57918b972df7674c94180a687977f7b26 Mon Sep 17 00:00:00 2001 From: Thomas Becker Date: Fri, 26 Aug 2011 19:58:15 +0200 Subject: [PATCH 03/12] 323311: HashLoginService uses PropertyUserStore now --- .../jetty/security/HashLoginService.java | 128 ++++-------------- 1 file changed, 27 insertions(+), 101 deletions(-) diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java index 0d6a7e45b7b..ab73707e1ce 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java @@ -13,21 +13,12 @@ package org.eclipse.jetty.security; -import java.io.File; -import java.io.FilenameFilter; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; import org.eclipse.jetty.http.security.Credential; +import org.eclipse.jetty.security.PropertyUserStore.UserListener; import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.util.Scanner; -import org.eclipse.jetty.util.Scanner.BulkListener; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; @@ -49,10 +40,11 @@ import org.eclipse.jetty.util.resource.Resource; * * If DIGEST Authentication is used, the password must be in a recoverable format, either plain text or OBF:. */ -public class HashLoginService extends MappedLoginService +public class HashLoginService extends MappedLoginService implements UserListener { private static final Logger LOG = Log.getLogger(HashLoginService.class); + private PropertyUserStore _propertyUserStore; private String _config; private Resource _configResource; private Scanner _scanner; @@ -129,45 +121,7 @@ public class HashLoginService extends MappedLoginService @Override public void loadUsers() throws IOException { - if (_config == null) - return; - _configResource = Resource.newResource(_config); - - if (LOG.isDebugEnabled()) LOG.debug("Load " + this + " from " + _config); - - Properties properties = new Properties(); - properties.load(_configResource.getInputStream()); - Set known = new HashSet(); - - for (Map.Entry entry : properties.entrySet()) - { - String username = ((String)entry.getKey()).trim(); - String credentials = ((String)entry.getValue()).trim(); - String roles = null; - int c = credentials.indexOf(','); - if (c > 0) - { - roles = credentials.substring(c + 1).trim(); - credentials = credentials.substring(0,c).trim(); - } - - if (username != null && username.length() > 0 && credentials != null && credentials.length() > 0) - { - String[] roleArray = IdentityService.NO_ROLES; - if (roles != null && roles.length() > 0) - roleArray = roles.split(","); - known.add(username); - putUser(username,Credential.getCredential(credentials),roleArray); - } - } - - Iterator users = _users.keySet().iterator(); - while (users.hasNext()) - { - String user = users.next(); - if (!known.contains(user)) - users.remove(); - } + // TODO: Consider refactoring MappedLoginService to not have to override with unused methods } /* ------------------------------------------------------------ */ @@ -177,58 +131,15 @@ public class HashLoginService extends MappedLoginService protected void doStart() throws Exception { super.doStart(); - - if (getRefreshInterval() > 0) + if (_propertyUserStore == null) { - _scanner = new Scanner(); - _scanner.setScanInterval(getRefreshInterval()); - List dirList = new ArrayList(1); - dirList.add(_configResource.getFile()); - _scanner.setScanDirs(dirList); - _scanner.setFilenameFilter(new FilenameFilter() - { - public boolean accept(File dir, String name) - { - File f = new File(dir,name); - try - { - if (f.compareTo(_configResource.getFile()) == 0) - return true; - } - catch (IOException e) - { - return false; - } - - return false; - } - - }); - _scanner.addListener(new BulkListener() - { - public void filesChanged(List filenames) throws Exception - { - if (filenames == null) - return; - if (filenames.isEmpty()) - return; - if (filenames.size() == 1) - { - Resource r = Resource.newResource(filenames.get(0)); - if (r.getFile().equals(_configResource.getFile())) - loadUsers(); - } - } - - public String toString() - { - return "HashLoginService$Scanner"; - } - - }); - _scanner.setReportExistingFilesOnStartup(false); - _scanner.setRecursive(false); - _scanner.start(); + if(Log.isDebugEnabled()) + Log.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _config + " refreshInterval: " + _refreshInterval); + _propertyUserStore = new PropertyUserStore(); + _propertyUserStore.setRefreshInterval(_refreshInterval); + _propertyUserStore.setConfig(_config); + _propertyUserStore.registerUserListener(this); + _propertyUserStore.start(); } } @@ -243,5 +154,20 @@ public class HashLoginService extends MappedLoginService _scanner.stop(); _scanner = null; } + + /* ------------------------------------------------------------ */ + public void update(String userName, Credential credential, String[] roleArray) + { + if (Log.isDebugEnabled()) + Log.debug("update: " + userName + " Roles: " + roleArray.length); + putUser(userName,credential,roleArray); + } + /* ------------------------------------------------------------ */ + public void remove(String userName) + { + if (Log.isDebugEnabled()) + Log.debug("remove: " + userName); + removeUser(userName); + } } From df0aab1f49b395fe4bb903fcef2c3d214a79dc9e Mon Sep 17 00:00:00 2001 From: Thomas Becker Date: Fri, 26 Aug 2011 20:00:02 +0200 Subject: [PATCH 04/12] PropertyUserStore: Code Format --- .../jaas/spi/PropertyFileLoginModule.java | 98 +++++++++---------- 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java index 67a207042ff..b10342e303d 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java @@ -31,108 +31,104 @@ import org.eclipse.jetty.util.log.Logger; /** * PropertyFileLoginModule - * - * + * + * */ public class PropertyFileLoginModule extends AbstractLoginModule { private static final Logger LOG = Log.getLogger(PropertyFileLoginModule.class); public static final String DEFAULT_FILENAME = "realm.properties"; - public static final Map> fileMap = new HashMap>(); - - private String propertyFileName; - - + public static final Map> fileMap = new HashMap>(); - /** + private String propertyFileName; + + /** * Read contents of the configured property file. * - * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map) + * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, + * java.util.Map) * @param subject * @param callbackHandler * @param sharedState * @param options */ - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map sharedState, Map options) + public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { - super.initialize(subject, callbackHandler, sharedState, options); + super.initialize(subject,callbackHandler,sharedState,options); loadProperties((String)options.get("file")); } - - - - public void loadProperties (String filename) + + public void loadProperties(String filename) { File propsFile; - + if (filename == null) { - propsFile = new File(System.getProperty("user.dir"), DEFAULT_FILENAME); - //look for a file called realm.properties in the current directory - //if that fails, look for a file called realm.properties in $jetty.home/etc + propsFile = new File(System.getProperty("user.dir"),DEFAULT_FILENAME); + // look for a file called realm.properties in the current directory + // if that fails, look for a file called realm.properties in $jetty.home/etc if (!propsFile.exists()) - propsFile = new File(System.getProperty("jetty.home"), DEFAULT_FILENAME); + propsFile = new File(System.getProperty("jetty.home"),DEFAULT_FILENAME); } else { propsFile = new File(filename); } - - //give up, can't find a property file to load + + // give up, can't find a property file to load if (!propsFile.exists()) { LOG.warn("No property file found"); throw new IllegalStateException ("No property file specified in login module configuration file"); } - - - + try { this.propertyFileName = propsFile.getCanonicalPath(); if (fileMap.get(propertyFileName) != null) { - if (LOG.isDebugEnabled()) {LOG.debug("Properties file "+propertyFileName+" already in cache, skipping load");} + if (Log.isDebugEnabled()) + { + Log.debug("Properties file " + propertyFileName + " already in cache, skipping load"); + } return; } - + Map userInfoMap = new HashMap(); Properties props = new Properties(); props.load(new FileInputStream(propsFile)); - Iterator> iter = props.entrySet().iterator(); - while(iter.hasNext()) + Iterator> iter = props.entrySet().iterator(); + while (iter.hasNext()) { - - Map.Entry entry = iter.next(); - String username=entry.getKey().toString().trim(); - String credentials=entry.getValue().toString().trim(); - String roles=null; - int c=credentials.indexOf(','); - if (c>0) + + Map.Entry entry = iter.next(); + String username = entry.getKey().toString().trim(); + String credentials = entry.getValue().toString().trim(); + String roles = null; + int c = credentials.indexOf(','); + if (c > 0) { - roles=credentials.substring(c+1).trim(); - credentials=credentials.substring(0,c).trim(); + roles = credentials.substring(c + 1).trim(); + credentials = credentials.substring(0,c).trim(); } - if (username!=null && username.length()>0 && - credentials!=null && credentials.length()>0) + if (username != null && username.length() > 0 && credentials != null && credentials.length() > 0) { ArrayList roleList = new ArrayList(); - if(roles!=null && roles.length()>0) + if (roles != null && roles.length() > 0) { StringTokenizer tok = new StringTokenizer(roles,", "); - + while (tok.hasMoreTokens()) roleList.add(tok.nextToken()); } - - userInfoMap.put(username, (new UserInfo(username, Credential.getCredential(credentials.toString()), roleList))); + + userInfoMap.put(username,(new UserInfo(username,Credential.getCredential(credentials.toString()),roleList))); } } - - fileMap.put(propertyFileName, userInfoMap); + + fileMap.put(propertyFileName,userInfoMap); } catch (Exception e) { @@ -141,13 +137,13 @@ public class PropertyFileLoginModule extends AbstractLoginModule } } - /** - * Don't implement this as we want to pre-fetch all of the - * users. + /** + * Don't implement this as we want to pre-fetch all of the users. + * * @param username * @throws Exception */ - public UserInfo getUserInfo (String username) throws Exception + public UserInfo getUserInfo(String username) throws Exception { Map userInfoMap = (Map)fileMap.get(propertyFileName); if (userInfoMap == null) From c17552ee50090a02dc11328dd31d4a5cd662d9cf Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Tue, 13 Sep 2011 15:44:37 -0500 Subject: [PATCH 05/12] [323311] apply 5th patch of thomas, also removed extra method on IdentityService since it appears not needed, moved behavior to loadUsers() method instead. --- .../jaas/spi/PropertyFileLoginModule.java | 133 +++++++----------- .../security/DefaultIdentityService.java | 3 + .../jetty/security/HashLoginService.java | 15 +- .../jetty/security/IdentityService.java | 2 +- .../jetty/security/PropertyUserStore.java | 38 ++++- .../jetty/security/PropertyUserStoreTest.java | 7 + 6 files changed, 105 insertions(+), 93 deletions(-) diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java index b10342e303d..d3e69878cc1 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java @@ -13,19 +13,18 @@ package org.eclipse.jetty.plus.jaas.spi; -import java.io.File; -import java.io.FileInputStream; -import java.util.ArrayList; +import java.security.Principal; +import java.util.Arrays; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; -import java.util.Properties; -import java.util.StringTokenizer; +import java.util.Set; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import org.eclipse.jetty.http.security.Credential; +import org.eclipse.jetty.security.PropertyUserStore; +import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -36,12 +35,14 @@ import org.eclipse.jetty.util.log.Logger; */ public class PropertyFileLoginModule extends AbstractLoginModule { + public static final String DEFAULT_FILENAME = "realm.properties"; + private static final Logger LOG = Log.getLogger(PropertyFileLoginModule.class); - public static final String DEFAULT_FILENAME = "realm.properties"; - public static final Map> fileMap = new HashMap>(); + private static Map _propertyUserStores = new HashMap(); - private String propertyFileName; + private int _refreshInterval = 0; + private String _filename = DEFAULT_FILENAME; /** * Read contents of the configured property file. @@ -56,99 +57,61 @@ public class PropertyFileLoginModule extends AbstractLoginModule public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { super.initialize(subject,callbackHandler,sharedState,options); - loadProperties((String)options.get("file")); + setupPropertyUserStore(options); } - public void loadProperties(String filename) + private void setupPropertyUserStore(Map options) { - File propsFile; + if (_propertyUserStores.get(_filename) == null) + { + parseConfig(options); - if (filename == null) - { - propsFile = new File(System.getProperty("user.dir"),DEFAULT_FILENAME); - // look for a file called realm.properties in the current directory - // if that fails, look for a file called realm.properties in $jetty.home/etc - if (!propsFile.exists()) - propsFile = new File(System.getProperty("jetty.home"),DEFAULT_FILENAME); - } - else - { - propsFile = new File(filename); - } + PropertyUserStore _propertyUserStore = new PropertyUserStore(); + _propertyUserStore.setConfig(_filename); + _propertyUserStore.setRefreshInterval(_refreshInterval); + LOG.debug("setupPropertyUserStore: Starting new PropertyUserStore. PropertiesFile: " + _filename + " refreshInterval: " + _refreshInterval); - // give up, can't find a property file to load - if (!propsFile.exists()) - { - LOG.warn("No property file found"); - throw new IllegalStateException ("No property file specified in login module configuration file"); - } - - try - { - this.propertyFileName = propsFile.getCanonicalPath(); - if (fileMap.get(propertyFileName) != null) + try { - if (Log.isDebugEnabled()) - { - Log.debug("Properties file " + propertyFileName + " already in cache, skipping load"); - } - return; + _propertyUserStore.start(); + } + catch (Exception e) + { + LOG.warn("Exception while starting propertyUserStore: ",e); } - Map userInfoMap = new HashMap(); - Properties props = new Properties(); - props.load(new FileInputStream(propsFile)); - Iterator> iter = props.entrySet().iterator(); - while (iter.hasNext()) - { - - Map.Entry entry = iter.next(); - String username = entry.getKey().toString().trim(); - String credentials = entry.getValue().toString().trim(); - String roles = null; - int c = credentials.indexOf(','); - if (c > 0) - { - roles = credentials.substring(c + 1).trim(); - credentials = credentials.substring(0,c).trim(); - } - - if (username != null && username.length() > 0 && credentials != null && credentials.length() > 0) - { - ArrayList roleList = new ArrayList(); - if (roles != null && roles.length() > 0) - { - StringTokenizer tok = new StringTokenizer(roles,", "); - - while (tok.hasMoreTokens()) - roleList.add(tok.nextToken()); - } - - userInfoMap.put(username,(new UserInfo(username,Credential.getCredential(credentials.toString()),roleList))); - } - } - - fileMap.put(propertyFileName,userInfoMap); - } - catch (Exception e) - { - LOG.warn("Error loading properties from file", e); - throw new RuntimeException(e); + _propertyUserStores.put(_filename,_propertyUserStore); } } + private void parseConfig(Map options) + { + _filename = (String)options.get("file") != null?(String)options.get("file"):DEFAULT_FILENAME; + String refreshIntervalString = (String)options.get("refreshInterval"); + _refreshInterval = refreshIntervalString == null?_refreshInterval:Integer.parseInt(refreshIntervalString); + } + /** * Don't implement this as we want to pre-fetch all of the users. * - * @param username + * @param userName * @throws Exception */ - public UserInfo getUserInfo(String username) throws Exception + public UserInfo getUserInfo(String userName) throws Exception { - Map userInfoMap = (Map)fileMap.get(propertyFileName); - if (userInfoMap == null) + PropertyUserStore propertyUserStore = _propertyUserStores.get(_filename); + if (propertyUserStore == null) + throw new IllegalStateException("PropertyUserStore should never be null here!"); + + UserIdentity userIdentity = propertyUserStore.getUserIdentity(userName); + if(userIdentity==null) return null; - return (UserInfo)userInfoMap.get(username); + + Set principals = userIdentity.getSubject().getPrincipals(); + String[] roles = principals.toArray(new String[principals.size()]); + Credential credential = (Credential)userIdentity.getSubject().getPrivateCredentials().iterator().next(); + LOG.debug("Found: " + userName + " in PropertyUserStore"); + return new UserInfo(userName, credential,Arrays.asList(roles)); } -} +} \ No newline at end of file diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java index 2b2b7462761..472da9c6654 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java @@ -17,6 +17,9 @@ import java.security.Principal; import javax.security.auth.Subject; +import org.eclipse.jetty.http.security.Credential; +import org.eclipse.jetty.security.MappedLoginService.KnownUser; +import org.eclipse.jetty.security.MappedLoginService.RolePrincipal; import org.eclipse.jetty.server.UserIdentity; diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java index ab73707e1ce..12b51f51502 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java @@ -131,10 +131,13 @@ public class HashLoginService extends MappedLoginService implements UserListener protected void doStart() throws Exception { super.doStart(); + if (_propertyUserStore == null) { - if(Log.isDebugEnabled()) - Log.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _config + " refreshInterval: " + _refreshInterval); + if(LOG.isDebugEnabled()) + { + LOG.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _config + " refreshInterval: " + _refreshInterval); + } _propertyUserStore = new PropertyUserStore(); _propertyUserStore.setRefreshInterval(_refreshInterval); _propertyUserStore.setConfig(_config); @@ -158,16 +161,16 @@ public class HashLoginService extends MappedLoginService implements UserListener /* ------------------------------------------------------------ */ public void update(String userName, Credential credential, String[] roleArray) { - if (Log.isDebugEnabled()) - Log.debug("update: " + userName + " Roles: " + roleArray.length); + if (LOG.isDebugEnabled()) + LOG.debug("update: " + userName + " Roles: " + roleArray.length); putUser(userName,credential,roleArray); } /* ------------------------------------------------------------ */ public void remove(String userName) { - if (Log.isDebugEnabled()) - Log.debug("remove: " + userName); + if (LOG.isDebugEnabled()) + LOG.debug("remove: " + userName); removeUser(userName); } } diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java index e05a000b2e0..216ae818d9b 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java @@ -14,9 +14,9 @@ package org.eclipse.jetty.security; import java.security.Principal; - import javax.security.auth.Subject; +import org.eclipse.jetty.http.security.Credential; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.UserIdentity; 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 7f49893030d..b7e64ac123b 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 @@ -3,7 +3,9 @@ package org.eclipse.jetty.security; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; +import java.security.Principal; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -11,7 +13,12 @@ import java.util.Map; import java.util.Properties; import java.util.Set; +import javax.security.auth.Subject; + import org.eclipse.jetty.http.security.Credential; +import org.eclipse.jetty.security.MappedLoginService.KnownUser; +import org.eclipse.jetty.security.MappedLoginService.RolePrincipal; +import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.util.Scanner; import org.eclipse.jetty.util.Scanner.BulkListener; import org.eclipse.jetty.util.component.AbstractLifeCycle; @@ -42,8 +49,10 @@ public class PropertyUserStore extends AbstractLifeCycle private Scanner _scanner; private int _refreshInterval = 0;// default is not to reload + private IdentityService _identityService = new DefaultIdentityService(); private boolean _firstLoad = true; // true if first load, false from that point on private final List _knownUsers = new ArrayList(); + private final Map _knownUserIdentities = new HashMap(); private List _listeners; /* ------------------------------------------------------------ */ @@ -57,6 +66,12 @@ public class PropertyUserStore extends AbstractLifeCycle { _config = config; } + + /* ------------------------------------------------------------ */ + public UserIdentity getUserIdentity(String userName) + { + return _knownUserIdentities.get(userName); + } /* ------------------------------------------------------------ */ /** @@ -119,9 +134,29 @@ public class PropertyUserStore extends AbstractLifeCycle { String[] roleArray = IdentityService.NO_ROLES; if (roles != null && roles.length() > 0) + { roleArray = roles.split(","); + } known.add(username); - notifyUpdate(username,Credential.getCredential(credentials),roleArray); + Credential credential = Credential.getCredential(credentials); + + Principal userPrincipal = new KnownUser(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 RolePrincipal(role)); + } + } + + subject.setReadOnly(); + + _knownUserIdentities.put(username,_identityService.newUserIdentity(subject,userPrincipal,roleArray)); + notifyUpdate(username,credential,roleArray); } } @@ -138,6 +173,7 @@ public class PropertyUserStore extends AbstractLifeCycle String user = users.next(); if (!known.contains(user)) { + _knownUserIdentities.remove(user); notifyRemove(user); } } diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/PropertyUserStoreTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/PropertyUserStoreTest.java index dde1df50bc1..68220b8dbca 100644 --- a/jetty-security/src/test/java/org/eclipse/jetty/security/PropertyUserStoreTest.java +++ b/jetty-security/src/test/java/org/eclipse/jetty/security/PropertyUserStoreTest.java @@ -78,6 +78,9 @@ public class PropertyUserStoreTest store.start(); + Assert.assertNotNull("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("tom")); + Assert.assertNotNull("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("dick")); + Assert.assertNotNull("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("harry")); Assert.assertEquals(3,userCount.get()); } @@ -117,7 +120,11 @@ public class PropertyUserStoreTest long start = System.currentTimeMillis(); while (userCount.get() < 4 && (System.currentTimeMillis() - start) < 10000) + { Thread.sleep(10); + } + + Assert.assertNotNull("Failed to retrieve UserIdentity from PropertyUserStore directly", store.getUserIdentity("skip")); Assert.assertEquals(4,userCount.get()); Assert.assertTrue(users.contains("skip")); From 2ef624e9fa4c125b60b785bf358b111a07f20eab Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Tue, 20 Sep 2011 10:11:08 -0500 Subject: [PATCH 06/12] add resource dir for tests --- jetty-servlet/src/test/resources/dispatchTest/dispatch.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 jetty-servlet/src/test/resources/dispatchTest/dispatch.txt diff --git a/jetty-servlet/src/test/resources/dispatchTest/dispatch.txt b/jetty-servlet/src/test/resources/dispatchTest/dispatch.txt new file mode 100644 index 00000000000..f3a34851d44 --- /dev/null +++ b/jetty-servlet/src/test/resources/dispatchTest/dispatch.txt @@ -0,0 +1 @@ +text \ No newline at end of file From 3091739b70b9cca0e612fbb8d3cac6ab7b70851b Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Tue, 20 Sep 2011 11:47:17 -0500 Subject: [PATCH 07/12] remove plugin versions we get from parent and remove groupId --- pom.xml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pom.xml b/pom.xml index fcb8e146e5c..4b45232f305 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,6 @@ jetty-parent 19-SNAPSHOT - org.eclipse.jetty jetty-project 7.5.2-SNAPSHOT Jetty :: Project @@ -245,7 +244,6 @@ org.codehaus.mojo findbugs-maven-plugin - 2.3.2 true true @@ -260,12 +258,10 @@ org.apache.maven.plugins maven-jxr-plugin - 2.2 org.apache.maven.plugins maven-javadoc-plugin - 2.8 true true @@ -275,7 +271,6 @@ org.apache.maven.plugins maven-pmd-plugin - 2.5 @@ -286,12 +281,10 @@ org.apache.maven.plugins maven-jxr-plugin - 2.2 org.apache.maven.plugins maven-javadoc-plugin - 2.8 512m true @@ -302,7 +295,6 @@ org.apache.maven.plugins maven-pmd-plugin - 2.5 1.5 @@ -313,7 +305,6 @@ org.codehaus.mojo findbugs-maven-plugin - 2.3.2 From bc86f5d154f0482eb2b1316c7b6a0e0061b33a92 Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Tue, 20 Sep 2011 14:08:30 -0500 Subject: [PATCH 08/12] update parent version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4b45232f305..9bbf848c240 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-parent - 19-SNAPSHOT + 19 jetty-project 7.5.2-SNAPSHOT From f6d26c20078fbf9df043c4a02fe1bf4b728a2c6f Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Tue, 20 Sep 2011 14:09:26 -0500 Subject: [PATCH 09/12] [Bug 358263] add method for osgi users to register a driver as Class.forName does not work for them --- .../server/session/JDBCSessionIdManager.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java index 8e73f3af1d0..ad5b244d761 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java @@ -18,6 +18,7 @@ import java.io.InputStream; import java.sql.Blob; import java.sql.Connection; import java.sql.DatabaseMetaData; +import java.sql.Driver; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -56,6 +57,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager protected final HashSet _sessionIds = new HashSet(); protected Server _server; + protected Driver _driver; protected String _driverClassName; protected String _connectionUrl; protected DataSource _datasource; @@ -184,6 +186,19 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager _connectionUrl=connectionUrl; } + /** + * Configure jdbc connection information via a jdbc Driver + * + * @param driverClass + * @param connectionUrl + */ + public void setDriverInfo (Driver driverClass, String connectionUrl) + { + _driver=driverClass; + _connectionUrl=connectionUrl; + } + + public String getDriverClassName() { return _driverClassName; @@ -461,7 +476,11 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager InitialContext ic = new InitialContext(); _datasource = (DataSource)ic.lookup(_jndiName); } - else if (_driverClassName!=null && _connectionUrl!=null) + else if ( _driver != null && _connectionUrl != null ) + { + DriverManager.registerDriver(_driver); + } + else if (_driverClassName != null && _connectionUrl != null) { Class.forName(_driverClassName); } From f0fe55165b6ff36c9440d3ba4272f64ebd232b10 Mon Sep 17 00:00:00 2001 From: Thomas Becker Date: Tue, 20 Sep 2011 10:19:23 +0200 Subject: [PATCH 10/12] SelectConnector.java code format --- .../java/org/eclipse/jetty/client/SelectConnector.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java b/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java index 333c4166ba4..f070951407e 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java @@ -103,12 +103,12 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector } else { - channel.configureBlocking( false ); + channel.configureBlocking(false); channel.connect(address.toSocketAddress()); - _selectorManager.register( channel, destination ); - ConnectTimeout connectTimeout = new ConnectTimeout(channel, destination); + _selectorManager.register(channel,destination); + ConnectTimeout connectTimeout = new ConnectTimeout(channel,destination); _httpClient.schedule(connectTimeout,_httpClient.getConnectTimeout()); - _connectingChannels.put(channel, connectTimeout); + _connectingChannels.put(channel,connectTimeout); } } From 4b7f8d79dd9465b561599e1635bb86f08d99d14b Mon Sep 17 00:00:00 2001 From: Thomas Becker Date: Tue, 20 Sep 2011 10:20:24 +0200 Subject: [PATCH 11/12] 358147: SelectConnector catch UnresolvedAddressException to avoid socket leak --- .../org/eclipse/jetty/client/SelectConnector.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java b/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java index f070951407e..caadb23c274 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java @@ -17,8 +17,10 @@ import java.io.IOException; import java.net.SocketTimeoutException; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; +import java.nio.channels.UnresolvedAddressException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; + import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSession; @@ -104,7 +106,15 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector else { channel.configureBlocking(false); - channel.connect(address.toSocketAddress()); + try + { + channel.connect(address.toSocketAddress()); + } + catch (UnresolvedAddressException ex) + { + channel.close(); + throw ex; + } _selectorManager.register(channel,destination); ConnectTimeout connectTimeout = new ConnectTimeout(channel,destination); _httpClient.schedule(connectTimeout,_httpClient.getConnectTimeout()); From 21ddd768f0edf75becbb65ca494ff3f4be1d9b3d Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Tue, 20 Sep 2011 14:26:17 -0500 Subject: [PATCH 12/12] [Bug 358147] Add catch for UnknownHostException to fix leaky file descriptor in client --- .../org/eclipse/jetty/client/SelectConnector.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java b/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java index caadb23c274..c2274ef5eda 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java @@ -15,6 +15,7 @@ package org.eclipse.jetty.client; import java.io.IOException; import java.net.SocketTimeoutException; +import java.net.UnknownHostException; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.nio.channels.UnresolvedAddressException; @@ -110,11 +111,17 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector { channel.connect(address.toSocketAddress()); } - catch (UnresolvedAddressException ex) + catch (UnresolvedAddressException uae) { channel.close(); - throw ex; + throw uae; } + catch ( UnknownHostException uhe ) + { + channel.close(); + throw uhe; + } + _selectorManager.register(channel,destination); ConnectTimeout connectTimeout = new ConnectTimeout(channel,destination); _httpClient.schedule(connectTimeout,_httpClient.getConnectTimeout());