Merge branch 'master' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project

This commit is contained in:
Greg Wilkins 2011-09-21 13:46:21 +10:00
commit fe489224e6
10 changed files with 203 additions and 241 deletions

View File

@ -15,10 +15,13 @@ 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;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
@ -103,12 +106,26 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
}
else
{
channel.configureBlocking( false );
channel.connect(address.toSocketAddress());
_selectorManager.register( channel, destination );
ConnectTimeout connectTimeout = new ConnectTimeout(channel, destination);
channel.configureBlocking(false);
try
{
channel.connect(address.toSocketAddress());
}
catch (UnresolvedAddressException uae)
{
channel.close();
throw uae;
}
catch ( UnknownHostException uhe )
{
channel.close();
throw uhe;
}
_selectorManager.register(channel,destination);
ConnectTimeout connectTimeout = new ConnectTimeout(channel,destination);
_httpClient.schedule(connectTimeout,_httpClient.getConnectTimeout());
_connectingChannels.put(channel, connectTimeout);
_connectingChannels.put(channel,connectTimeout);
}
}

View File

@ -13,146 +13,105 @@
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;
/**
* PropertyFileLoginModule
*
*
*
*
*/
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<String, Map<String, UserInfo>> fileMap = new HashMap<String, Map<String, UserInfo>>();
private String propertyFileName;
private static Map<String, PropertyUserStore> _propertyUserStores = new HashMap<String, PropertyUserStore>();
/**
private int _refreshInterval = 0;
private String _filename = DEFAULT_FILENAME;
/**
* 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<String,?> sharedState, Map<String,?> options)
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options)
{
super.initialize(subject, callbackHandler, sharedState, options);
loadProperties((String)options.get("file"));
super.initialize(subject,callbackHandler,sharedState,options);
setupPropertyUserStore(options);
}
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
if (!propsFile.exists())
propsFile = new File(System.getProperty("jetty.home"), DEFAULT_FILENAME);
}
else
{
propsFile = new File(filename);
}
//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");}
return;
}
Map<String, UserInfo> userInfoMap = new HashMap<String, UserInfo>();
Properties props = new Properties();
props.load(new FileInputStream(propsFile));
Iterator<Map.Entry<Object,Object>> iter = props.entrySet().iterator();
while(iter.hasNext())
{
Map.Entry<Object,Object> 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<String> roleList = new ArrayList<String>();
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)
private void setupPropertyUserStore(Map<String, ?> options)
{
if (_propertyUserStores.get(_filename) == null)
{
LOG.warn("Error loading properties from file", e);
throw new RuntimeException(e);
parseConfig(options);
PropertyUserStore _propertyUserStore = new PropertyUserStore();
_propertyUserStore.setConfig(_filename);
_propertyUserStore.setRefreshInterval(_refreshInterval);
LOG.debug("setupPropertyUserStore: Starting new PropertyUserStore. PropertiesFile: " + _filename + " refreshInterval: " + _refreshInterval);
try
{
_propertyUserStore.start();
}
catch (Exception e)
{
LOG.warn("Exception while starting propertyUserStore: ",e);
}
_propertyUserStores.put(_filename,_propertyUserStore);
}
}
/**
* Don't implement this as we want to pre-fetch all of the
* users.
* @param username
private void parseConfig(Map<String, ?> 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
* @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<Principal> 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));
}
}
}

View File

@ -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;

View File

@ -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;
@ -36,27 +27,24 @@ 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.
* <P>
* 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:
*
* <PRE>
* username: password [,rolename ...]
* </PRE>
*
* 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
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;
@ -72,14 +60,14 @@ public class HashLoginService extends MappedLoginService
{
setName(name);
}
/* ------------------------------------------------------------ */
public HashLoginService(String name, String config)
{
setName(name);
setConfig(config);
}
/* ------------------------------------------------------------ */
public String getConfig()
{
@ -89,7 +77,7 @@ public class HashLoginService extends MappedLoginService
/* ------------------------------------------------------------ */
public void getConfig(String config)
{
_config=config;
_config = config;
}
/* ------------------------------------------------------------ */
@ -100,11 +88,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,52 +116,14 @@ public class HashLoginService extends MappedLoginService
{
return null;
}
/* ------------------------------------------------------------ */
@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<String> known = new HashSet<String>();
for (Map.Entry<Object, Object> 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<String> 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
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
@ -183,54 +132,17 @@ public class HashLoginService extends MappedLoginService
{
super.doStart();
if (getRefreshInterval() > 0)
if (_propertyUserStore == null)
{
_scanner = new Scanner();
_scanner.setScanInterval(getRefreshInterval());
List<File> dirList = new ArrayList<File>(1);
dirList.add(_configResource.getFile());
_scanner.setScanDirs(dirList);
_scanner.setFilenameFilter(new FilenameFilter()
if(LOG.isDebugEnabled())
{
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<String> 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();
LOG.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _config + " refreshInterval: " + _refreshInterval);
}
_propertyUserStore = new PropertyUserStore();
_propertyUserStore.setRefreshInterval(_refreshInterval);
_propertyUserStore.setConfig(_config);
_propertyUserStore.registerUserListener(this);
_propertyUserStore.start();
}
}
@ -241,9 +153,24 @@ public class HashLoginService extends MappedLoginService
protected void doStop() throws Exception
{
super.doStop();
if (_scanner != null) _scanner.stop();
if (_scanner != null)
_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);
}
}

View File

@ -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;

View File

@ -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<String> _knownUsers = new ArrayList<String>();
private final Map<String, UserIdentity> _knownUserIdentities = new HashMap<String, UserIdentity>();
private List<UserListener> _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);
}
}
@ -201,15 +237,17 @@ public class PropertyUserStore extends AbstractLifeCycle
_scanner.addListener(new BulkListener()
{
public void filesChanged(List filenames) throws Exception
public void filesChanged(List<String> 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();
}
}

View File

@ -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"));

View File

@ -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<String> _sessionIds = new HashSet<String>();
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);
}

View File

@ -0,0 +1 @@
text

11
pom.xml
View File

@ -3,9 +3,8 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-parent</artifactId>
<version>19-SNAPSHOT</version>
<version>19</version>
</parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>7.5.2-SNAPSHOT</version>
<name>Jetty :: Project</name>
@ -245,7 +244,6 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<findbugsXmlOutput>true</findbugsXmlOutput>
<xmlOutput>true</xmlOutput>
@ -260,12 +258,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8</version>
<configuration>
<docfilessubdirs>true</docfilessubdirs>
<detectLinks>true</detectLinks>
@ -275,7 +271,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>2.5</version>
</plugin>
</plugins>
</pluginManagement>
@ -286,12 +281,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8</version>
<configuration>
<maxmemory>512m</maxmemory>
<docfilessubdirs>true</docfilessubdirs>
@ -302,7 +295,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>2.5</version>
<configuration>
<targetJdk>1.5</targetJdk>
<rulesets>
@ -313,7 +305,6 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.3.2</version>
</plugin>
</plugins>
</reporting>