483059 Remove cache of authenticated users
This commit is contained in:
parent
18a3af1951
commit
81b2a6a4de
|
@ -289,6 +289,7 @@ public abstract class AbstractLoginModule implements LoginModule
|
||||||
public boolean logout() throws LoginException
|
public boolean logout() throws LoginException
|
||||||
{
|
{
|
||||||
this.currentUser.unsetJAASInfo(this.subject);
|
this.currentUser.unsetJAASInfo(this.subject);
|
||||||
|
this.currentUser = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,8 @@ public class PropertyFileLoginModule extends AbstractLoginModule
|
||||||
private int _refreshInterval = 0;
|
private int _refreshInterval = 0;
|
||||||
private String _filename = DEFAULT_FILENAME;
|
private String _filename = DEFAULT_FILENAME;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read contents of the configured property file.
|
* Read contents of the configured property file.
|
||||||
*
|
*
|
||||||
|
@ -73,7 +75,6 @@ public class PropertyFileLoginModule extends AbstractLoginModule
|
||||||
{
|
{
|
||||||
PropertyUserStore propertyUserStore = new PropertyUserStore();
|
PropertyUserStore propertyUserStore = new PropertyUserStore();
|
||||||
propertyUserStore.setConfig(_filename);
|
propertyUserStore.setConfig(_filename);
|
||||||
propertyUserStore.setRefreshInterval(_refreshInterval);
|
|
||||||
|
|
||||||
PropertyUserStore prev = _propertyUserStores.putIfAbsent(_filename, propertyUserStore);
|
PropertyUserStore prev = _propertyUserStores.putIfAbsent(_filename, propertyUserStore);
|
||||||
if (prev == null)
|
if (prev == null)
|
||||||
|
|
|
@ -22,14 +22,16 @@ import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.security.AbstractLoginService;
|
||||||
import org.eclipse.jetty.security.ConstraintMapping;
|
import org.eclipse.jetty.security.ConstraintMapping;
|
||||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||||
import org.eclipse.jetty.security.HashLoginService;
|
|
||||||
import org.eclipse.jetty.server.LocalConnector;
|
import org.eclipse.jetty.server.LocalConnector;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
|
@ -38,6 +40,7 @@ import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||||
import org.eclipse.jetty.util.B64Code;
|
import org.eclipse.jetty.util.B64Code;
|
||||||
import org.eclipse.jetty.util.security.Constraint;
|
import org.eclipse.jetty.util.security.Constraint;
|
||||||
|
import org.eclipse.jetty.util.security.Credential;
|
||||||
import org.eclipse.jetty.util.security.Password;
|
import org.eclipse.jetty.util.security.Password;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -48,6 +51,43 @@ public class JaspiTest
|
||||||
{
|
{
|
||||||
Server _server;
|
Server _server;
|
||||||
LocalConnector _connector;
|
LocalConnector _connector;
|
||||||
|
public class TestLoginService extends AbstractLoginService
|
||||||
|
{
|
||||||
|
protected Map<String, UserPrincipal> _users = new HashMap<>();
|
||||||
|
protected Map<String, String[]> _roles = new HashMap();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public TestLoginService(String name)
|
||||||
|
{
|
||||||
|
setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putUser (String username, Credential credential, String[] roles)
|
||||||
|
{
|
||||||
|
UserPrincipal userPrincipal = new UserPrincipal(username,credential);
|
||||||
|
_users.put(username, userPrincipal);
|
||||||
|
_roles.put(username, roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.AbstractLoginService#loadRoleInfo(org.eclipse.jetty.security.AbstractLoginService.UserPrincipal)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String[] loadRoleInfo(UserPrincipal user)
|
||||||
|
{
|
||||||
|
return _roles.get(user.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.AbstractLoginService#loadUserInfo(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected UserPrincipal loadUserInfo(String username)
|
||||||
|
{
|
||||||
|
return _users.get(username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() throws Exception
|
public void before() throws Exception
|
||||||
|
@ -60,7 +100,7 @@ public class JaspiTest
|
||||||
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||||
_server.setHandler(contexts);
|
_server.setHandler(contexts);
|
||||||
|
|
||||||
HashLoginService loginService = new HashLoginService("TestRealm");
|
TestLoginService loginService = new TestLoginService("TestRealm");
|
||||||
loginService.putUser("user",new Password("password"),new String[]{"users"});
|
loginService.putUser("user",new Password("password"),new String[]{"users"});
|
||||||
loginService.putUser("admin",new Password("secret"),new String[]{"users","admins"});
|
loginService.putUser("admin",new Password("secret"),new String[]{"users","admins"});
|
||||||
_server.addBean(loginService);
|
_server.addBean(loginService);
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
<New class="org.eclipse.jetty.security.HashLoginService">
|
<New class="org.eclipse.jetty.security.HashLoginService">
|
||||||
<Set name="name">Test Realm</Set>
|
<Set name="name">Test Realm</Set>
|
||||||
<Set name="config"><Property name="jetty.home" default="src/test/config"/>realm.properties</Set>
|
<Set name="config"><Property name="jetty.home" default="src/test/config"/>realm.properties</Set>
|
||||||
<Set name="refreshInterval">0</Set>
|
|
||||||
</New>
|
</New>
|
||||||
</Arg>
|
</Arg>
|
||||||
</Call>
|
</Call>
|
||||||
|
|
|
@ -32,14 +32,12 @@ import java.util.Locale;
|
||||||
import javax.naming.InitialContext;
|
import javax.naming.InitialContext;
|
||||||
import javax.naming.NameNotFoundException;
|
import javax.naming.NameNotFoundException;
|
||||||
import javax.naming.NamingException;
|
import javax.naming.NamingException;
|
||||||
import javax.servlet.ServletRequest;
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
|
import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
|
||||||
|
import org.eclipse.jetty.security.AbstractLoginService;
|
||||||
import org.eclipse.jetty.security.IdentityService;
|
import org.eclipse.jetty.security.IdentityService;
|
||||||
import org.eclipse.jetty.security.MappedLoginService;
|
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.server.UserIdentity;
|
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.security.Credential;
|
import org.eclipse.jetty.util.security.Credential;
|
||||||
|
@ -51,7 +49,7 @@ import org.eclipse.jetty.util.security.Credential;
|
||||||
* Obtain user/password/role information from a database
|
* Obtain user/password/role information from a database
|
||||||
* via jndi DataSource.
|
* via jndi DataSource.
|
||||||
*/
|
*/
|
||||||
public class DataSourceLoginService extends MappedLoginService
|
public class DataSourceLoginService extends AbstractLoginService
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(DataSourceLoginService.class);
|
private static final Logger LOG = Log.getLogger(DataSourceLoginService.class);
|
||||||
|
|
||||||
|
@ -68,8 +66,6 @@ public class DataSourceLoginService extends MappedLoginService
|
||||||
private String _userRoleTableName = "user_roles";
|
private String _userRoleTableName = "user_roles";
|
||||||
private String _userRoleTableUserKey = "user_id";
|
private String _userRoleTableUserKey = "user_id";
|
||||||
private String _userRoleTableRoleKey = "role_id";
|
private String _userRoleTableRoleKey = "role_id";
|
||||||
private int _cacheMs = 30000;
|
|
||||||
private long _lastPurge = 0;
|
|
||||||
private String _userSql;
|
private String _userSql;
|
||||||
private String _roleSql;
|
private String _roleSql;
|
||||||
private boolean _createTables = false;
|
private boolean _createTables = false;
|
||||||
|
@ -80,7 +76,7 @@ public class DataSourceLoginService extends MappedLoginService
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class DBUser extends KnownUser
|
public class DBUserPrincipal extends UserPrincipal
|
||||||
{
|
{
|
||||||
private int _key;
|
private int _key;
|
||||||
|
|
||||||
|
@ -88,7 +84,7 @@ public class DataSourceLoginService extends MappedLoginService
|
||||||
* @param name
|
* @param name
|
||||||
* @param credential
|
* @param credential
|
||||||
*/
|
*/
|
||||||
public DBUser(String name, Credential credential, int key)
|
public DBUserPrincipal(String name, Credential credential, int key)
|
||||||
{
|
{
|
||||||
super(name, credential);
|
super(name, credential);
|
||||||
_key = key;
|
_key = key;
|
||||||
|
@ -292,81 +288,14 @@ public class DataSourceLoginService extends MappedLoginService
|
||||||
_userRoleTableRoleKey = roleTableRoleKey;
|
_userRoleTableRoleKey = roleTableRoleKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public void setCacheMs (int ms)
|
|
||||||
{
|
|
||||||
_cacheMs=ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public int getCacheMs ()
|
|
||||||
{
|
|
||||||
return _cacheMs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
@Override
|
|
||||||
protected void loadUsers()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Load user's info from database.
|
|
||||||
*
|
|
||||||
* @param userName the user name
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected UserIdentity loadUser (String userName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
try (Connection connection = getConnection();
|
|
||||||
PreparedStatement statement1 = connection.prepareStatement(_userSql))
|
|
||||||
{
|
|
||||||
statement1.setObject(1, userName);
|
|
||||||
try (ResultSet rs1 = statement1.executeQuery())
|
|
||||||
{
|
|
||||||
if (rs1.next())
|
|
||||||
{
|
|
||||||
int key = rs1.getInt(_userTableKey);
|
|
||||||
String credentials = rs1.getString(_userTablePasswordField);
|
|
||||||
|
|
||||||
List<String> roles = new ArrayList<String>();
|
|
||||||
try (PreparedStatement statement2 = connection.prepareStatement(_roleSql))
|
|
||||||
{
|
|
||||||
statement2.setInt(1, key);
|
|
||||||
try (ResultSet rs2 = statement2.executeQuery())
|
|
||||||
{
|
|
||||||
while (rs2.next())
|
|
||||||
{
|
|
||||||
roles.add(rs2.getString(_roleTableRoleField));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return putUser(userName, Credential.getCredential(credentials), roles.toArray(new String[roles.size()]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (NamingException e)
|
|
||||||
{
|
|
||||||
LOG.warn("No datasource for "+_jndiName, e);
|
|
||||||
}
|
|
||||||
catch (SQLException e)
|
|
||||||
{
|
|
||||||
LOG.warn("Problem loading user info for "+userName, e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see org.eclipse.jetty.security.MappedLoginService#loadUserInfo(java.lang.String)
|
* @see org.eclipse.jetty.security.MappedLoginService#loadUserInfo(java.lang.String)
|
||||||
* @Override
|
* @Override
|
||||||
*/
|
*/
|
||||||
public KnownUser loadUserInfo (String username)
|
public UserPrincipal loadUserInfo (String username)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -381,7 +310,7 @@ public class DataSourceLoginService extends MappedLoginService
|
||||||
int key = rs1.getInt(_userTableKey);
|
int key = rs1.getInt(_userTableKey);
|
||||||
String credentials = rs1.getString(_userTablePasswordField);
|
String credentials = rs1.getString(_userTablePasswordField);
|
||||||
|
|
||||||
return new DBUser(username, Credential.getCredential(credentials), key);
|
return new DBUserPrincipal(username, Credential.getCredential(credentials), key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -397,13 +326,15 @@ public class DataSourceLoginService extends MappedLoginService
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @see org.eclipse.jetty.security.MappedLoginService#loadRoleInfo(org.eclipse.jetty.security.MappedLoginService.KnownUser)
|
* @see org.eclipse.jetty.security.MappedLoginService#loadRoleInfo(org.eclipse.jetty.security.UserPrincipal.KnownUser)
|
||||||
* @Override
|
* @Override
|
||||||
*/
|
*/
|
||||||
public String[] loadRoleInfo (KnownUser user)
|
public String[] loadRoleInfo (UserPrincipal user)
|
||||||
{
|
{
|
||||||
DBUser dbuser = (DBUser)user;
|
DBUserPrincipal dbuser = (DBUserPrincipal)user;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -440,19 +371,7 @@ public class DataSourceLoginService extends MappedLoginService
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
@Override
|
|
||||||
public UserIdentity login(String username, Object credentials, ServletRequest request)
|
|
||||||
{
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
if (now - _lastPurge > _cacheMs || _cacheMs == 0)
|
|
||||||
{
|
|
||||||
_users.clear();
|
|
||||||
_lastPurge = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.login(username,credentials, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
|
@ -509,6 +428,11 @@ public class DataSourceLoginService extends MappedLoginService
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @throws NamingException
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
private void prepareTables()
|
private void prepareTables()
|
||||||
throws NamingException, SQLException
|
throws NamingException, SQLException
|
||||||
{
|
{
|
||||||
|
@ -610,6 +534,12 @@ public class DataSourceLoginService extends MappedLoginService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
* @throws NamingException
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
private Connection getConnection ()
|
private Connection getConnection ()
|
||||||
throws NamingException, SQLException
|
throws NamingException, SQLException
|
||||||
{
|
{
|
||||||
|
|
|
@ -240,7 +240,6 @@
|
||||||
<New class="org.eclipse.jetty.security.jaspi.modules.HashLoginService">
|
<New class="org.eclipse.jetty.security.jaspi.modules.HashLoginService">
|
||||||
<Set name="name">Test Realm</Set>
|
<Set name="name">Test Realm</Set>
|
||||||
<Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
|
<Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
|
||||||
<Set name="refreshInterval">0</Set>
|
|
||||||
</New>
|
</New>
|
||||||
</Item>
|
</Item>
|
||||||
</Array>
|
</Array>
|
||||||
|
|
|
@ -0,0 +1,270 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2015 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 java.io.Serializable;
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.UserIdentity;
|
||||||
|
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.security.Credential;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AbstractLoginService
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractLoginService extends AbstractLifeCycle implements LoginService
|
||||||
|
{
|
||||||
|
private static final Logger LOG = Log.getLogger(AbstractLoginService.class);
|
||||||
|
|
||||||
|
protected IdentityService _identityService=new DefaultIdentityService();
|
||||||
|
protected String _name;
|
||||||
|
protected boolean _fullValidate = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* RolePrincipal
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class RolePrincipal implements Principal,Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 2998397924051854402L;
|
||||||
|
private final String _roleName;
|
||||||
|
public RolePrincipal(String name)
|
||||||
|
{
|
||||||
|
_roleName=name;
|
||||||
|
}
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return _roleName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* UserPrincipal
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class UserPrincipal implements Principal,Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = -6226920753748399662L;
|
||||||
|
private final String _name;
|
||||||
|
private final Credential _credential;
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------- */
|
||||||
|
public UserPrincipal(String name,Credential credential)
|
||||||
|
{
|
||||||
|
_name=name;
|
||||||
|
_credential=credential;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------- */
|
||||||
|
public boolean authenticate(Object credentials)
|
||||||
|
{
|
||||||
|
return _credential!=null && _credential.check(credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------- */
|
||||||
|
public boolean authenticate (Credential c)
|
||||||
|
{
|
||||||
|
return(_credential != null && c != null && _credential.equals(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------- */
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
protected abstract String[] loadRoleInfo (UserPrincipal user);
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
protected abstract UserPrincipal loadUserInfo (String username);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.LoginService#getName()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/** Set the identityService.
|
||||||
|
* @param identityService the identityService to set
|
||||||
|
*/
|
||||||
|
public void setIdentityService(IdentityService identityService)
|
||||||
|
{
|
||||||
|
if (isRunning())
|
||||||
|
throw new IllegalStateException("Running");
|
||||||
|
_identityService = identityService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/** Set the name.
|
||||||
|
* @param name the name to set
|
||||||
|
*/
|
||||||
|
public void setName(String name)
|
||||||
|
{
|
||||||
|
if (isRunning())
|
||||||
|
throw new IllegalStateException("Running");
|
||||||
|
_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return this.getClass().getSimpleName()+"["+_name+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.LoginService#login(java.lang.String, java.lang.Object, javax.servlet.ServletRequest)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public UserIdentity login(String username, Object credentials, ServletRequest request)
|
||||||
|
{
|
||||||
|
if (username == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
UserPrincipal userPrincipal = loadUserInfo(username);
|
||||||
|
if (userPrincipal.authenticate(credentials))
|
||||||
|
{
|
||||||
|
//safe to load the roles
|
||||||
|
String[] roles = loadRoleInfo(userPrincipal);
|
||||||
|
|
||||||
|
Subject subject = new Subject();
|
||||||
|
subject.getPrincipals().add(userPrincipal);
|
||||||
|
subject.getPrivateCredentials().add(userPrincipal._credential);
|
||||||
|
if (roles!=null)
|
||||||
|
for (String role : roles)
|
||||||
|
subject.getPrincipals().add(new RolePrincipal(role));
|
||||||
|
subject.setReadOnly();
|
||||||
|
return _identityService.newUserIdentity(subject,userPrincipal,roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.LoginService#validate(org.eclipse.jetty.server.UserIdentity)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean validate(UserIdentity user)
|
||||||
|
{
|
||||||
|
if (!isFullValidate())
|
||||||
|
return true; //if we have a user identity it must be valid
|
||||||
|
|
||||||
|
//Do a full validation back against the user store
|
||||||
|
UserPrincipal fresh = loadUserInfo(user.getUserPrincipal().getName());
|
||||||
|
if (fresh == null)
|
||||||
|
return false; //user no longer exists
|
||||||
|
|
||||||
|
if (user.getUserPrincipal() instanceof UserPrincipal)
|
||||||
|
{
|
||||||
|
System.err.println("VALIDATING user "+fresh.getName());
|
||||||
|
return fresh.authenticate(((UserPrincipal)user.getUserPrincipal())._credential);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("UserPrincipal not KnownUser"); //can't validate
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.LoginService#getIdentityService()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public IdentityService getIdentityService()
|
||||||
|
{
|
||||||
|
return _identityService;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.LoginService#logout(org.eclipse.jetty.server.UserIdentity)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void logout(UserIdentity user)
|
||||||
|
{
|
||||||
|
//Override in subclasses
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isFullValidate()
|
||||||
|
{
|
||||||
|
return _fullValidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @param fullValidate
|
||||||
|
*/
|
||||||
|
public void setFullValidate(boolean fullValidate)
|
||||||
|
{
|
||||||
|
_fullValidate = fullValidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,7 +23,6 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jetty.security.MappedLoginService.KnownUser;
|
|
||||||
import org.eclipse.jetty.security.PropertyUserStore.UserListener;
|
import org.eclipse.jetty.security.PropertyUserStore.UserListener;
|
||||||
import org.eclipse.jetty.server.UserIdentity;
|
import org.eclipse.jetty.server.UserIdentity;
|
||||||
import org.eclipse.jetty.util.Scanner;
|
import org.eclipse.jetty.util.Scanner;
|
||||||
|
@ -49,45 +48,17 @@ import org.eclipse.jetty.util.security.Credential;
|
||||||
* <p>
|
* <p>
|
||||||
* 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 implements UserListener
|
public class HashLoginService extends AbstractLoginService
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(HashLoginService.class);
|
private static final Logger LOG = Log.getLogger(HashLoginService.class);
|
||||||
|
|
||||||
private PropertyUserStore _propertyUserStore;
|
protected PropertyUserStore _propertyUserStore;
|
||||||
private String _config;
|
protected String _config;
|
||||||
private Resource _configResource;
|
protected Resource _configResource;
|
||||||
private Scanner _scanner;
|
protected boolean hotReload = false; // default is not to reload
|
||||||
private boolean hotReload = false; // default is not to reload
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class HashKnownUser extends KnownUser
|
|
||||||
{
|
|
||||||
String[] _roles;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param name
|
|
||||||
* @param credential
|
|
||||||
*/
|
|
||||||
public HashKnownUser(String name, Credential credential)
|
|
||||||
{
|
|
||||||
super(name, credential);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void setRoles (String[] roles)
|
|
||||||
{
|
|
||||||
_roles = roles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getRoles()
|
|
||||||
{
|
|
||||||
return _roles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public HashLoginService()
|
public HashLoginService()
|
||||||
|
@ -161,46 +132,11 @@ public class HashLoginService extends MappedLoginService implements UserListener
|
||||||
this.hotReload = enable;
|
this.hotReload = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* sets the refresh interval (in seconds)
|
|
||||||
* @param sec the refresh interval
|
|
||||||
* @deprecated use {@link #setHotReload(boolean)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void setRefreshInterval(int sec)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @return refresh interval in seconds for how often the properties file should be checked for changes
|
|
||||||
* @deprecated use {@link #isHotReload()} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public int getRefreshInterval()
|
|
||||||
{
|
|
||||||
return (hotReload)?1:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
protected UserIdentity loadUser(String username)
|
protected String[] loadRoleInfo(UserPrincipal user)
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
@Override
|
|
||||||
public void loadUsers() throws IOException
|
|
||||||
{
|
|
||||||
// TODO: Consider refactoring MappedLoginService to not have to override with unused methods
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String[] loadRoleInfo(KnownUser user)
|
|
||||||
{
|
{
|
||||||
UserIdentity id = _propertyUserStore.getUserIdentity(user.getName());
|
UserIdentity id = _propertyUserStore.getUserIdentity(user.getName());
|
||||||
if (id == null)
|
if (id == null)
|
||||||
|
@ -218,13 +154,17 @@ public class HashLoginService extends MappedLoginService implements UserListener
|
||||||
return list.toArray(new String[roles.size()]);
|
return list.toArray(new String[roles.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
protected KnownUser loadUserInfo(String userName)
|
protected UserPrincipal loadUserInfo(String userName)
|
||||||
{
|
{
|
||||||
UserIdentity id = _propertyUserStore.getUserIdentity(userName);
|
UserIdentity id = _propertyUserStore.getUserIdentity(userName);
|
||||||
if (id != null)
|
if (id != null)
|
||||||
{
|
{
|
||||||
return (KnownUser)id.getUserPrincipal();
|
return (UserPrincipal)id.getUserPrincipal();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -249,7 +189,6 @@ public class HashLoginService extends MappedLoginService implements UserListener
|
||||||
_propertyUserStore = new PropertyUserStore();
|
_propertyUserStore = new PropertyUserStore();
|
||||||
_propertyUserStore.setHotReload(hotReload);
|
_propertyUserStore.setHotReload(hotReload);
|
||||||
_propertyUserStore.setConfigPath(_config);
|
_propertyUserStore.setConfigPath(_config);
|
||||||
_propertyUserStore.registerUserListener(this);
|
|
||||||
_propertyUserStore.start();
|
_propertyUserStore.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -262,28 +201,5 @@ public class HashLoginService extends MappedLoginService implements UserListener
|
||||||
protected void doStop() throws Exception
|
protected void doStop() throws Exception
|
||||||
{
|
{
|
||||||
super.doStop();
|
super.doStop();
|
||||||
if (_scanner != null)
|
|
||||||
_scanner.stop();
|
|
||||||
_scanner = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
@Override
|
|
||||||
public void update(String userName, Credential credential, String[] roleArray)
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("update: " + userName + " Roles: " + roleArray.length);
|
|
||||||
//TODO need to remove and replace the authenticated user?
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
@Override
|
|
||||||
public void remove(String userName)
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("remove: " + userName);
|
|
||||||
removeUser(userName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ import org.eclipse.jetty.util.security.Credential;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class JDBCLoginService extends MappedLoginService
|
public class JDBCLoginService extends AbstractLoginService
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(JDBCLoginService.class);
|
private static final Logger LOG = Log.getLogger(JDBCLoginService.class);
|
||||||
|
|
||||||
|
@ -71,8 +71,6 @@ public class JDBCLoginService extends MappedLoginService
|
||||||
protected String _userTableKey;
|
protected String _userTableKey;
|
||||||
protected String _userTablePasswordField;
|
protected String _userTablePasswordField;
|
||||||
protected String _roleTableRoleField;
|
protected String _roleTableRoleField;
|
||||||
protected int _cacheTime;
|
|
||||||
protected long _lastHashPurge;
|
|
||||||
protected Connection _con;
|
protected Connection _con;
|
||||||
protected String _userSql;
|
protected String _userSql;
|
||||||
protected String _roleSql;
|
protected String _roleSql;
|
||||||
|
@ -83,7 +81,7 @@ public class JDBCLoginService extends MappedLoginService
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class JDBCKnownUser extends KnownUser
|
public class JDBCUserPrincipal extends UserPrincipal
|
||||||
{
|
{
|
||||||
int _userKey;
|
int _userKey;
|
||||||
|
|
||||||
|
@ -91,7 +89,7 @@ public class JDBCLoginService extends MappedLoginService
|
||||||
* @param name
|
* @param name
|
||||||
* @param credential
|
* @param credential
|
||||||
*/
|
*/
|
||||||
public JDBCKnownUser(String name, Credential credential, int key)
|
public JDBCUserPrincipal(String name, Credential credential, int key)
|
||||||
{
|
{
|
||||||
super(name, credential);
|
super(name, credential);
|
||||||
_userKey = key;
|
_userKey = key;
|
||||||
|
@ -162,20 +160,18 @@ public class JDBCLoginService extends MappedLoginService
|
||||||
String _userRoleTable = properties.getProperty("userroletable");
|
String _userRoleTable = properties.getProperty("userroletable");
|
||||||
String _userRoleTableUserKey = properties.getProperty("userroletableuserkey");
|
String _userRoleTableUserKey = properties.getProperty("userroletableuserkey");
|
||||||
String _userRoleTableRoleKey = properties.getProperty("userroletablerolekey");
|
String _userRoleTableRoleKey = properties.getProperty("userroletablerolekey");
|
||||||
_cacheTime = new Integer(properties.getProperty("cachetime"));
|
|
||||||
|
|
||||||
if (_jdbcDriver == null || _jdbcDriver.equals("")
|
if (_jdbcDriver == null || _jdbcDriver.equals("")
|
||||||
|| _url == null
|
|| _url == null
|
||||||
|| _url.equals("")
|
|| _url.equals("")
|
||||||
|| _userName == null
|
|| _userName == null
|
||||||
|| _userName.equals("")
|
|| _userName.equals("")
|
||||||
|| _password == null
|
|| _password == null)
|
||||||
|| _cacheTime < 0)
|
|
||||||
{
|
{
|
||||||
LOG.warn("UserRealm " + getName() + " has not been properly configured");
|
LOG.warn("UserRealm " + getName() + " has not been properly configured");
|
||||||
}
|
}
|
||||||
_cacheTime *= 1000;
|
|
||||||
_lastHashPurge = 0;
|
|
||||||
_userSql = "select " + _userTableKey + "," + _userTablePasswordField + " from " + _userTable + " where " + _userTableUserField + " = ?";
|
_userSql = "select " + _userTableKey + "," + _userTablePasswordField + " from " + _userTable + " where " + _userTableUserField + " = ?";
|
||||||
_roleSql = "select r." + _roleTableRoleField
|
_roleSql = "select r." + _roleTableRoleField
|
||||||
+ " from "
|
+ " from "
|
||||||
|
@ -235,80 +231,15 @@ public class JDBCLoginService extends MappedLoginService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
@Override
|
|
||||||
public UserIdentity login(String username, Object credentials, ServletRequest request)
|
|
||||||
{
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
if (now - _lastHashPurge > _cacheTime || _cacheTime == 0)
|
|
||||||
{
|
|
||||||
_users.clear();
|
|
||||||
_lastHashPurge = now;
|
|
||||||
closeConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.login(username,credentials, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
@Override
|
|
||||||
protected void loadUsers()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Deprecated
|
|
||||||
protected UserIdentity loadUser(String username)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (null == _con)
|
|
||||||
connectDatabase();
|
|
||||||
|
|
||||||
if (null == _con)
|
|
||||||
throw new SQLException("Can't connect to database");
|
|
||||||
|
|
||||||
try (PreparedStatement stat1 = _con.prepareStatement(_userSql))
|
|
||||||
{
|
|
||||||
stat1.setObject(1, username);
|
|
||||||
try (ResultSet rs1 = stat1.executeQuery())
|
|
||||||
{
|
|
||||||
if (rs1.next())
|
|
||||||
{
|
|
||||||
int key = rs1.getInt(_userTableKey);
|
|
||||||
String credentials = rs1.getString(_userTablePasswordField);
|
|
||||||
|
|
||||||
|
|
||||||
List<String> roles = new ArrayList<String>();
|
|
||||||
|
|
||||||
try (PreparedStatement stat2 = _con.prepareStatement(_roleSql))
|
|
||||||
{
|
|
||||||
stat2.setInt(1, key);
|
|
||||||
try (ResultSet rs2 = stat2.executeQuery())
|
|
||||||
{
|
|
||||||
while (rs2.next())
|
|
||||||
roles.add(rs2.getString(_roleTableRoleField));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return putUser(username, Credential.getCredential(credentials), roles.toArray(new String[roles.size()]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (SQLException e)
|
|
||||||
{
|
|
||||||
LOG.warn("UserRealm " + getName() + " could not load user information from database", e);
|
|
||||||
closeConnection();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see org.eclipse.jetty.security.MappedLoginService#loadUserInfo(java.lang.String)
|
* @see org.eclipse.jetty.security.MappedLoginService#loadUserInfo(java.lang.String)
|
||||||
* @Override
|
* @Override
|
||||||
*/
|
*/
|
||||||
public KnownUser loadUserInfo (String username)
|
public UserPrincipal loadUserInfo (String username)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -328,7 +259,7 @@ public class JDBCLoginService extends MappedLoginService
|
||||||
int key = rs1.getInt(_userTableKey);
|
int key = rs1.getInt(_userTableKey);
|
||||||
String credentials = rs1.getString(_userTablePasswordField);
|
String credentials = rs1.getString(_userTablePasswordField);
|
||||||
|
|
||||||
return new JDBCKnownUser (username, Credential.getCredential(credentials), key);
|
return new JDBCUserPrincipal (username, Credential.getCredential(credentials), key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,14 +274,14 @@ public class JDBCLoginService extends MappedLoginService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @see org.eclipse.jetty.security.MappedLoginService#loadRoleInfo(org.eclipse.jetty.security.MappedLoginService.KnownUser)
|
* @see org.eclipse.jetty.security.MappedLoginService#loadRoleInfo(org.eclipse.jetty.security.UserPrincipal.KnownUser)
|
||||||
* @Override
|
* @Override
|
||||||
*/
|
*/
|
||||||
public String[] loadRoleInfo (KnownUser user)
|
public String[] loadRoleInfo (UserPrincipal user)
|
||||||
{
|
{
|
||||||
JDBCKnownUser jdbcUser = (JDBCKnownUser)user;
|
JDBCUserPrincipal jdbcUser = (JDBCUserPrincipal)user;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -385,7 +316,19 @@ public class JDBCLoginService extends MappedLoginService
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void doStop() throws Exception
|
||||||
|
{
|
||||||
|
closeConnection();
|
||||||
|
super.doStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Close an existing connection
|
* Close an existing connection
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,375 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2015 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 java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.security.Principal;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
|
|
||||||
import javax.security.auth.Subject;
|
|
||||||
import javax.servlet.ServletRequest;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.server.UserIdentity;
|
|
||||||
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.security.Credential;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* A login service that keeps UserIdentities in a concurrent map
|
|
||||||
* either as the source or a cache of the users.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public abstract class MappedLoginService extends AbstractLifeCycle implements LoginService
|
|
||||||
{
|
|
||||||
private static final Logger LOG = Log.getLogger(MappedLoginService.class);
|
|
||||||
|
|
||||||
protected IdentityService _identityService=new DefaultIdentityService();
|
|
||||||
protected String _name;
|
|
||||||
protected final ConcurrentMap<String, UserIdentity> _users=new ConcurrentHashMap<String, UserIdentity>();
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
protected MappedLoginService()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Get the name.
|
|
||||||
* @return the name
|
|
||||||
*/
|
|
||||||
public String getName()
|
|
||||||
{
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Get the identityService.
|
|
||||||
* @return the identityService
|
|
||||||
*/
|
|
||||||
public IdentityService getIdentityService()
|
|
||||||
{
|
|
||||||
return _identityService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Get the users.
|
|
||||||
* @return the users
|
|
||||||
*/
|
|
||||||
public ConcurrentMap<String, UserIdentity> getUsers()
|
|
||||||
{
|
|
||||||
return _users;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Set the identityService.
|
|
||||||
* @param identityService the identityService to set
|
|
||||||
*/
|
|
||||||
public void setIdentityService(IdentityService identityService)
|
|
||||||
{
|
|
||||||
if (isRunning())
|
|
||||||
throw new IllegalStateException("Running");
|
|
||||||
_identityService = identityService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Set the name.
|
|
||||||
* @param name the name to set
|
|
||||||
*/
|
|
||||||
public void setName(String name)
|
|
||||||
{
|
|
||||||
if (isRunning())
|
|
||||||
throw new IllegalStateException("Running");
|
|
||||||
_name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Set the users.
|
|
||||||
* @param users the users to set
|
|
||||||
*/
|
|
||||||
public void setUsers(Map<String, UserIdentity> users)
|
|
||||||
{
|
|
||||||
if (isRunning())
|
|
||||||
throw new IllegalStateException("Running");
|
|
||||||
_users.clear();
|
|
||||||
_users.putAll(users);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void doStart() throws Exception
|
|
||||||
{
|
|
||||||
loadUsers();
|
|
||||||
super.doStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
@Override
|
|
||||||
protected void doStop() throws Exception
|
|
||||||
{
|
|
||||||
super.doStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public void logout(UserIdentity identity)
|
|
||||||
{
|
|
||||||
LOG.debug("logout {}",identity);
|
|
||||||
|
|
||||||
//TODO should remove the user?????
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return this.getClass().getSimpleName()+"["+_name+"]";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Put user into realm.
|
|
||||||
* Called by implementations to put the user data loaded from
|
|
||||||
* file/db etc into the user structure.
|
|
||||||
* @param userName User name
|
|
||||||
* @param info a UserIdentity instance, or a String password or Credential instance
|
|
||||||
* @return User instance
|
|
||||||
*/
|
|
||||||
protected synchronized UserIdentity putUser(String userName, Object info)
|
|
||||||
{
|
|
||||||
final UserIdentity identity;
|
|
||||||
if (info instanceof UserIdentity)
|
|
||||||
identity=(UserIdentity)info;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Credential credential = (info instanceof Credential)?(Credential)info:Credential.getCredential(info.toString());
|
|
||||||
|
|
||||||
Principal userPrincipal = new KnownUser(userName,credential);
|
|
||||||
Subject subject = new Subject();
|
|
||||||
subject.getPrincipals().add(userPrincipal);
|
|
||||||
subject.getPrivateCredentials().add(credential);
|
|
||||||
subject.setReadOnly();
|
|
||||||
identity=_identityService.newUserIdentity(subject,userPrincipal,IdentityService.NO_ROLES);
|
|
||||||
}
|
|
||||||
|
|
||||||
_users.put(userName,identity);
|
|
||||||
return identity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Put user into realm.
|
|
||||||
* @param userName The user to add
|
|
||||||
* @param credential The users Credentials
|
|
||||||
* @param roles The users roles
|
|
||||||
* @return UserIdentity
|
|
||||||
*/
|
|
||||||
public synchronized UserIdentity putUser(String userName, Credential credential, String[] roles)
|
|
||||||
{
|
|
||||||
Principal userPrincipal = new KnownUser(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 RolePrincipal(role));
|
|
||||||
|
|
||||||
subject.setReadOnly();
|
|
||||||
UserIdentity identity=_identityService.newUserIdentity(subject,userPrincipal,roles);
|
|
||||||
_users.put(userName,identity);
|
|
||||||
return identity;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public synchronized UserIdentity putUser (KnownUser userPrincipal, String[] roles)
|
|
||||||
{
|
|
||||||
Subject subject = new Subject();
|
|
||||||
subject.getPrincipals().add(userPrincipal);
|
|
||||||
subject.getPrivateCredentials().add(userPrincipal._credential);
|
|
||||||
if (roles!=null)
|
|
||||||
for (String role : roles)
|
|
||||||
subject.getPrincipals().add(new RolePrincipal(role));
|
|
||||||
subject.setReadOnly();
|
|
||||||
UserIdentity identity=_identityService.newUserIdentity(subject,userPrincipal,roles);
|
|
||||||
_users.put(userPrincipal._name,identity);
|
|
||||||
return identity;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public void removeUser(String username)
|
|
||||||
{
|
|
||||||
_users.remove(username);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @see org.eclipse.jetty.security.LoginService#login(java.lang.String, java.lang.Object, ServletRequest)
|
|
||||||
*/
|
|
||||||
public UserIdentity login(String username, Object credentials, ServletRequest request)
|
|
||||||
{
|
|
||||||
if (username == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
UserIdentity user = _users.get(username);
|
|
||||||
|
|
||||||
if (user==null)
|
|
||||||
{
|
|
||||||
KnownUser userPrincipal = loadUserInfo(username);
|
|
||||||
if (userPrincipal.authenticate(credentials))
|
|
||||||
{
|
|
||||||
//safe to load the roles
|
|
||||||
String[] roles = loadRoleInfo(userPrincipal);
|
|
||||||
user = putUser(userPrincipal, roles);
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UserPrincipal principal = (UserPrincipal)user.getUserPrincipal();
|
|
||||||
if (principal.authenticate(credentials))
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public boolean validate(UserIdentity user)
|
|
||||||
{
|
|
||||||
if (_users.containsKey(user.getUserPrincipal().getName()))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (loadUser(user.getUserPrincipal().getName())!=null)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
protected abstract String[] loadRoleInfo (KnownUser user);
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
protected abstract KnownUser loadUserInfo (String username);
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
protected abstract UserIdentity loadUser(String username);
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
protected abstract void loadUsers() throws IOException;
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public interface UserPrincipal extends Principal,Serializable
|
|
||||||
{
|
|
||||||
boolean authenticate(Object credentials);
|
|
||||||
public boolean isAuthenticated();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public static class RolePrincipal implements Principal,Serializable
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 2998397924051854402L;
|
|
||||||
private final String _roleName;
|
|
||||||
public RolePrincipal(String name)
|
|
||||||
{
|
|
||||||
_roleName=name;
|
|
||||||
}
|
|
||||||
public String getName()
|
|
||||||
{
|
|
||||||
return _roleName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public static class Anonymous implements UserPrincipal,Serializable
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1097640442553284845L;
|
|
||||||
|
|
||||||
public boolean isAuthenticated()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName()
|
|
||||||
{
|
|
||||||
return "Anonymous";
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean authenticate(Object credentials)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public static class KnownUser implements UserPrincipal,Serializable
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = -6226920753748399662L;
|
|
||||||
private final String _name;
|
|
||||||
private final Credential _credential;
|
|
||||||
|
|
||||||
/* -------------------------------------------------------- */
|
|
||||||
public KnownUser(String name,Credential credential)
|
|
||||||
{
|
|
||||||
_name=name;
|
|
||||||
_credential=credential;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------- */
|
|
||||||
public boolean authenticate(Object credentials)
|
|
||||||
{
|
|
||||||
return _credential!=null && _credential.check(credentials);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public String getName()
|
|
||||||
{
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------- */
|
|
||||||
public boolean isAuthenticated()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------- */
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -33,8 +33,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import javax.security.auth.Subject;
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
import org.eclipse.jetty.security.MappedLoginService.KnownUser;
|
|
||||||
import org.eclipse.jetty.security.MappedLoginService.RolePrincipal;
|
|
||||||
import org.eclipse.jetty.server.UserIdentity;
|
import org.eclipse.jetty.server.UserIdentity;
|
||||||
import org.eclipse.jetty.util.PathWatcher;
|
import org.eclipse.jetty.util.PathWatcher;
|
||||||
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
|
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
|
||||||
|
@ -64,17 +63,17 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(PropertyUserStore.class);
|
private static final Logger LOG = Log.getLogger(PropertyUserStore.class);
|
||||||
|
|
||||||
private Path _configPath;
|
protected Path _configPath;
|
||||||
private Resource _configResource;
|
protected Resource _configResource;
|
||||||
|
|
||||||
private PathWatcher pathWatcher;
|
protected PathWatcher pathWatcher;
|
||||||
private boolean hotReload = false; // default is not to reload
|
protected boolean hotReload = false; // default is not to reload
|
||||||
|
|
||||||
private IdentityService _identityService = new DefaultIdentityService();
|
protected IdentityService _identityService = new DefaultIdentityService();
|
||||||
private boolean _firstLoad = true; // true if first load, false from that point on
|
protected boolean _firstLoad = true; // true if first load, false from that point on
|
||||||
private final List<String> _knownUsers = new ArrayList<String>();
|
protected final List<String> _knownUsers = new ArrayList<String>();
|
||||||
private final Map<String, UserIdentity> _knownUserIdentities = new HashMap<String, UserIdentity>();
|
protected final Map<String, UserIdentity> _knownUserIdentities = new HashMap<String, UserIdentity>();
|
||||||
private List<UserListener> _listeners;
|
protected List<UserListener> _listeners;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the config (as a string)
|
* Get the config (as a string)
|
||||||
|
@ -186,27 +185,7 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.
|
||||||
this.hotReload = enable;
|
this.hotReload = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* sets the refresh interval (in seconds)
|
|
||||||
* @param sec the refresh interval
|
|
||||||
* @deprecated use {@link #setHotReload(boolean)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void setRefreshInterval(int sec)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @return refresh interval in seconds for how often the properties file should be checked for changes
|
|
||||||
* @deprecated use {@link #isHotReload()} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public int getRefreshInterval()
|
|
||||||
{
|
|
||||||
return (hotReload)?1:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
|
@ -221,7 +200,7 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private void loadUsers() throws IOException
|
protected void loadUsers() throws IOException
|
||||||
{
|
{
|
||||||
if (_configPath == null)
|
if (_configPath == null)
|
||||||
return;
|
return;
|
||||||
|
@ -259,7 +238,7 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.
|
||||||
known.add(username);
|
known.add(username);
|
||||||
Credential credential = Credential.getCredential(credentials);
|
Credential credential = Credential.getCredential(credentials);
|
||||||
|
|
||||||
Principal userPrincipal = new KnownUser(username,credential);
|
Principal userPrincipal = new AbstractLoginService.UserPrincipal(username,credential);
|
||||||
Subject subject = new Subject();
|
Subject subject = new Subject();
|
||||||
subject.getPrincipals().add(userPrincipal);
|
subject.getPrincipals().add(userPrincipal);
|
||||||
subject.getPrivateCredentials().add(credential);
|
subject.getPrivateCredentials().add(credential);
|
||||||
|
@ -268,7 +247,7 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.
|
||||||
{
|
{
|
||||||
for (String role : roleArray)
|
for (String role : roleArray)
|
||||||
{
|
{
|
||||||
subject.getPrincipals().add(new RolePrincipal(role));
|
subject.getPrincipals().add(new AbstractLoginService.RolePrincipal(role));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,8 @@ public class AliasedConstraintTest
|
||||||
private static Server server;
|
private static Server server;
|
||||||
private static LocalConnector connector;
|
private static LocalConnector connector;
|
||||||
private static ConstraintSecurityHandler security;
|
private static ConstraintSecurityHandler security;
|
||||||
|
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void startServer() throws Exception
|
public static void startServer() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -73,7 +74,8 @@ public class AliasedConstraintTest
|
||||||
ContextHandler context = new ContextHandler();
|
ContextHandler context = new ContextHandler();
|
||||||
SessionHandler session = new SessionHandler();
|
SessionHandler session = new SessionHandler();
|
||||||
|
|
||||||
HashLoginService loginService = new HashLoginService(TEST_REALM);
|
TestLoginService loginService = new TestLoginService(TEST_REALM);
|
||||||
|
|
||||||
loginService.putUser("user0",new Password("password"),new String[] {});
|
loginService.putUser("user0",new Password("password"),new String[] {});
|
||||||
loginService.putUser("user",new Password("password"),new String[] { "user" });
|
loginService.putUser("user",new Password("password"),new String[] { "user" });
|
||||||
loginService.putUser("user2",new Password("password"),new String[] { "user" });
|
loginService.putUser("user2",new Password("password"),new String[] { "user" });
|
||||||
|
|
|
@ -85,7 +85,8 @@ public class ConstraintTest
|
||||||
ContextHandler _context = new ContextHandler();
|
ContextHandler _context = new ContextHandler();
|
||||||
SessionHandler _session = new SessionHandler();
|
SessionHandler _session = new SessionHandler();
|
||||||
|
|
||||||
HashLoginService _loginService = new HashLoginService(TEST_REALM);
|
TestLoginService _loginService = new TestLoginService(TEST_REALM);
|
||||||
|
|
||||||
_loginService.putUser("user0", new Password("password"), new String[]{});
|
_loginService.putUser("user0", new Password("password"), new String[]{});
|
||||||
_loginService.putUser("user",new Password("password"), new String[] {"user"});
|
_loginService.putUser("user",new Password("password"), new String[] {"user"});
|
||||||
_loginService.putUser("user2",new Password("password"), new String[] {"user"});
|
_loginService.putUser("user2",new Password("password"), new String[] {"user"});
|
||||||
|
|
|
@ -69,8 +69,9 @@ public class SpecExampleConstraintTest
|
||||||
ContextHandler _context = new ContextHandler();
|
ContextHandler _context = new ContextHandler();
|
||||||
_session = new SessionHandler();
|
_session = new SessionHandler();
|
||||||
|
|
||||||
HashLoginService _loginService = new HashLoginService(TEST_REALM);
|
TestLoginService _loginService = new TestLoginService(TEST_REALM);
|
||||||
_loginService.putUser("fred",new Password("password"));
|
|
||||||
|
_loginService.putUser("fred",new Password("password"), IdentityService.NO_ROLES);
|
||||||
_loginService.putUser("harry",new Password("password"), new String[] {"HOMEOWNER"});
|
_loginService.putUser("harry",new Password("password"), new String[] {"HOMEOWNER"});
|
||||||
_loginService.putUser("chris",new Password("password"), new String[] {"CONTRACTOR"});
|
_loginService.putUser("chris",new Password("password"), new String[] {"CONTRACTOR"});
|
||||||
_loginService.putUser("steven", new Password("password"), new String[] {"SALESCLERK"});
|
_loginService.putUser("steven", new Password("password"), new String[] {"SALESCLERK"});
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2015 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 java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.security.Credential;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TestLoginService
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TestLoginService extends AbstractLoginService
|
||||||
|
{
|
||||||
|
protected Map<String, UserPrincipal> _users = new HashMap<>();
|
||||||
|
protected Map<String, String[]> _roles = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public TestLoginService(String name)
|
||||||
|
{
|
||||||
|
setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putUser (String username, Credential credential, String[] roles)
|
||||||
|
{
|
||||||
|
UserPrincipal userPrincipal = new UserPrincipal(username,credential);
|
||||||
|
_users.put(username, userPrincipal);
|
||||||
|
_roles.put(username, roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.AbstractLoginService#loadRoleInfo(org.eclipse.jetty.security.AbstractLoginService.UserPrincipal)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String[] loadRoleInfo(UserPrincipal user)
|
||||||
|
{
|
||||||
|
return _roles.get(user.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.AbstractLoginService#loadUserInfo(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected UserPrincipal loadUserInfo(String username)
|
||||||
|
{
|
||||||
|
return _users.get(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -104,7 +104,20 @@ public abstract class Credential implements Serializable
|
||||||
String passwd = credentials.toString();
|
String passwd = credentials.toString();
|
||||||
return _cooked.equals(UnixCrypt.crypt(passwd, _cooked));
|
return _cooked.equals(UnixCrypt.crypt(passwd, _cooked));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals (Object credential)
|
||||||
|
{
|
||||||
|
if (!(credential instanceof Crypt))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Crypt c = (Crypt)credential;
|
||||||
|
|
||||||
|
return _cooked.equals(c._cooked);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static String crypt(String user, String pw)
|
public static String crypt(String user, String pw)
|
||||||
{
|
{
|
||||||
return "CRYPT:" + UnixCrypt.crypt(pw, user);
|
return "CRYPT:" + UnixCrypt.crypt(pw, user);
|
||||||
|
@ -167,12 +180,7 @@ public abstract class Credential implements Serializable
|
||||||
}
|
}
|
||||||
else if (credentials instanceof MD5)
|
else if (credentials instanceof MD5)
|
||||||
{
|
{
|
||||||
MD5 md5 = (MD5) credentials;
|
return equals((MD5)credentials);
|
||||||
if (_digest.length != md5._digest.length) return false;
|
|
||||||
boolean digestMismatch = false;
|
|
||||||
for (int i = 0; i < _digest.length; i++)
|
|
||||||
digestMismatch |= (_digest[i] != md5._digest[i]);
|
|
||||||
return !digestMismatch;
|
|
||||||
}
|
}
|
||||||
else if (credentials instanceof Credential)
|
else if (credentials instanceof Credential)
|
||||||
{
|
{
|
||||||
|
@ -192,6 +200,24 @@ public abstract class Credential implements Serializable
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (obj instanceof MD5)
|
||||||
|
{
|
||||||
|
MD5 md5 = (MD5) obj;
|
||||||
|
if (_digest.length != md5._digest.length) return false;
|
||||||
|
boolean digestMismatch = false;
|
||||||
|
for (int i = 0; i < _digest.length; i++)
|
||||||
|
digestMismatch |= (_digest[i] != md5._digest[i]);
|
||||||
|
return !digestMismatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public static String digest(String password)
|
public static String digest(String password)
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2015 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.util.security;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.security.Credential.Crypt;
|
||||||
|
import org.eclipse.jetty.util.security.Credential.MD5;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CredentialTest
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CredentialTest
|
||||||
|
{
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCrypt() throws Exception
|
||||||
|
{
|
||||||
|
Crypt c1 = (Crypt)Credential.getCredential(Crypt.crypt("fred", "abc123"));
|
||||||
|
Crypt c2 = (Crypt)Credential.getCredential(Crypt.crypt("fred", "abc123"));
|
||||||
|
|
||||||
|
Crypt c3 = (Crypt)Credential.getCredential(Crypt.crypt("fred", "xyz123"));
|
||||||
|
|
||||||
|
Credential c4 = Credential.getCredential(Crypt.crypt("fred", "xyz123"));
|
||||||
|
|
||||||
|
assertTrue(c1.equals(c2));
|
||||||
|
assertTrue(c2.equals(c1));
|
||||||
|
assertFalse(c1.equals(c3));
|
||||||
|
assertFalse(c3.equals(c1));
|
||||||
|
assertFalse(c3.equals(c2));
|
||||||
|
assertTrue(c4.equals(c3));
|
||||||
|
assertFalse(c4.equals(c1));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMD5() throws Exception
|
||||||
|
{
|
||||||
|
MD5 m1 = (MD5)Credential.getCredential(MD5.digest("123foo"));
|
||||||
|
MD5 m2 = (MD5)Credential.getCredential(MD5.digest("123foo"));
|
||||||
|
MD5 m3 = (MD5)Credential.getCredential(MD5.digest("123boo"));
|
||||||
|
|
||||||
|
assertTrue(m1.equals(m2));
|
||||||
|
assertTrue(m2.equals(m1));
|
||||||
|
assertFalse(m3.equals(m1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPassword() throws Exception
|
||||||
|
{
|
||||||
|
Password p1 = new Password(Password.obfuscate("abc123"));
|
||||||
|
Credential p2 = Credential.getCredential(Password.obfuscate("abc123"));
|
||||||
|
|
||||||
|
assertTrue (p1.equals(p2));
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,9 @@ import java.net.URI;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
|
@ -39,6 +42,7 @@ import org.eclipse.jetty.client.util.BytesContentProvider;
|
||||||
import org.eclipse.jetty.client.util.DigestAuthentication;
|
import org.eclipse.jetty.client.util.DigestAuthentication;
|
||||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
|
import org.eclipse.jetty.security.AbstractLoginService;
|
||||||
import org.eclipse.jetty.security.ConstraintMapping;
|
import org.eclipse.jetty.security.ConstraintMapping;
|
||||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||||
import org.eclipse.jetty.security.HashLoginService;
|
import org.eclipse.jetty.security.HashLoginService;
|
||||||
|
@ -55,6 +59,7 @@ import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.eclipse.jetty.util.TypeUtil;
|
import org.eclipse.jetty.util.TypeUtil;
|
||||||
import org.eclipse.jetty.util.security.Constraint;
|
import org.eclipse.jetty.util.security.Constraint;
|
||||||
|
import org.eclipse.jetty.util.security.Credential;
|
||||||
import org.eclipse.jetty.util.security.Password;
|
import org.eclipse.jetty.util.security.Password;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
@ -79,6 +84,44 @@ public class DigestPostTest
|
||||||
public volatile static String _received = null;
|
public volatile static String _received = null;
|
||||||
private static Server _server;
|
private static Server _server;
|
||||||
|
|
||||||
|
public static class TestLoginService extends AbstractLoginService
|
||||||
|
{
|
||||||
|
protected Map<String, UserPrincipal> users = new HashMap<>();
|
||||||
|
protected Map<String, String[]> roles = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
public TestLoginService(String name)
|
||||||
|
{
|
||||||
|
setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putUser (String username, Credential credential, String[] rolenames)
|
||||||
|
{
|
||||||
|
UserPrincipal userPrincipal = new UserPrincipal(username,credential);
|
||||||
|
users.put(username, userPrincipal);
|
||||||
|
roles.put(username, rolenames);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.AbstractLoginService#loadRoleInfo(org.eclipse.jetty.security.AbstractLoginService.UserPrincipal)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String[] loadRoleInfo(UserPrincipal user)
|
||||||
|
{
|
||||||
|
return roles.get(user.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.AbstractLoginService#loadUserInfo(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected UserPrincipal loadUserInfo(String username)
|
||||||
|
{
|
||||||
|
return users.get(username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUpServer()
|
public static void setUpServer()
|
||||||
{
|
{
|
||||||
|
@ -91,7 +134,7 @@ public class DigestPostTest
|
||||||
context.setContextPath("/test");
|
context.setContextPath("/test");
|
||||||
context.addServlet(PostServlet.class,"/");
|
context.addServlet(PostServlet.class,"/");
|
||||||
|
|
||||||
HashLoginService realm = new HashLoginService("test");
|
TestLoginService realm = new TestLoginService("test");
|
||||||
realm.putUser("testuser",new Password("password"),new String[]{"test"});
|
realm.putUser("testuser",new Password("password"),new String[]{"test"});
|
||||||
_server.addBean(realm);
|
_server.addBean(realm);
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,6 @@ public class DataSourceLoginServiceTest
|
||||||
private static HttpClient _client;
|
private static HttpClient _client;
|
||||||
private static String __realm = "DSRealm";
|
private static String __realm = "DSRealm";
|
||||||
private static URI _baseUri;
|
private static URI _baseUri;
|
||||||
private static final int __cacheInterval = 200;
|
|
||||||
private static DatabaseLoginServiceTestServer _testServer;
|
private static DatabaseLoginServiceTestServer _testServer;
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,7 +123,6 @@ public class DataSourceLoginServiceTest
|
||||||
loginService.setUserRoleTableUserKey("user_id");
|
loginService.setUserRoleTableUserKey("user_id");
|
||||||
loginService.setJndiName("dstest");
|
loginService.setJndiName("dstest");
|
||||||
loginService.setName(__realm);
|
loginService.setName(__realm);
|
||||||
loginService.setCacheMs(__cacheInterval);
|
|
||||||
if (_testServer != null)
|
if (_testServer != null)
|
||||||
loginService.setServer(_testServer.getServer());
|
loginService.setServer(_testServer.getServer());
|
||||||
|
|
||||||
|
@ -154,7 +152,7 @@ public class DataSourceLoginServiceTest
|
||||||
String newpwd = String.valueOf(System.currentTimeMillis());
|
String newpwd = String.valueOf(System.currentTimeMillis());
|
||||||
|
|
||||||
changePassword("jetty", newpwd);
|
changePassword("jetty", newpwd);
|
||||||
TimeUnit.MILLISECONDS.sleep(2*__cacheInterval); //pause to ensure cache invalidates
|
|
||||||
|
|
||||||
startClient("jetty", newpwd);
|
startClient("jetty", newpwd);
|
||||||
|
|
||||||
|
|
|
@ -54,9 +54,8 @@ detected.
|
||||||
<Set name="name">Test Realm</Set>
|
<Set name="name">Test Realm</Set>
|
||||||
<Set name="config"><Property name="this.web-inf.url"/>realm.properties</Set>
|
<Set name="config"><Property name="this.web-inf.url"/>realm.properties</Set>
|
||||||
<!-- To enable reload of realm when properties change, uncomment the following lines -->
|
<!-- To enable reload of realm when properties change, uncomment the following lines -->
|
||||||
<!-- changing refreshInterval (in seconds) as desired -->
|
|
||||||
<!--
|
<!--
|
||||||
<Set name="refreshInterval">5</Set>
|
<Set name="hotReload">false</Set>
|
||||||
<Call name="start"></Call>
|
<Call name="start"></Call>
|
||||||
-->
|
-->
|
||||||
</New>
|
</New>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<New class="org.eclipse.jetty.security.HashLoginService">
|
<New class="org.eclipse.jetty.security.HashLoginService">
|
||||||
<Set name="name">Test Realm</Set>
|
<Set name="name">Test Realm</Set>
|
||||||
<Set name="config"><Property name="jetty.demo.realm" default="etc/realm.properties"/></Set>
|
<Set name="config"><Property name="jetty.demo.realm" default="etc/realm.properties"/></Set>
|
||||||
<Set name="refreshInterval">0</Set>
|
<Set name="hotReload">false</Set>
|
||||||
</New>
|
</New>
|
||||||
</Arg>
|
</Arg>
|
||||||
</Call>
|
</Call>
|
||||||
|
|
|
@ -81,9 +81,8 @@ detected.
|
||||||
<Set name="name">Test Realm</Set>
|
<Set name="name">Test Realm</Set>
|
||||||
<Set name="config"><SystemProperty name="jetty.base" default="."/>/etc/realm.properties</Set>
|
<Set name="config"><SystemProperty name="jetty.base" default="."/>/etc/realm.properties</Set>
|
||||||
<!-- To enable reload of realm when properties change, uncomment the following lines -->
|
<!-- To enable reload of realm when properties change, uncomment the following lines -->
|
||||||
<!-- changing refreshInterval (in seconds) as desired -->
|
|
||||||
<!--
|
<!--
|
||||||
<Set name="refreshInterval">5</Set>
|
<Set name="hotReload">true</Set>
|
||||||
<Call name="start"></Call>
|
<Call name="start"></Call>
|
||||||
-->
|
-->
|
||||||
</New>
|
</New>
|
||||||
|
|
Loading…
Reference in New Issue