Refactor jaas login sequence to only fetch role data if user is authenticated according to that module.
This commit is contained in:
parent
e296995b2f
commit
c7ab05a0b8
|
@ -21,7 +21,6 @@ package org.eclipse.jetty.jaas.spi;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -61,6 +60,24 @@ public abstract class AbstractDatabaseLoginModule extends AbstractLoginModule
|
||||||
public abstract Connection getConnection () throws Exception;
|
public abstract Connection getConnection () throws Exception;
|
||||||
|
|
||||||
|
|
||||||
|
public class JDBCUserInfo extends UserInfo
|
||||||
|
{
|
||||||
|
public JDBCUserInfo (String userName, Credential credential)
|
||||||
|
{
|
||||||
|
super(userName, credential);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> doFetchRoles ()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
return getRoles(getUserName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------ */
|
/* ------------------------------------------------ */
|
||||||
/** Load info from database
|
/** Load info from database
|
||||||
|
@ -92,8 +109,22 @@ public abstract class AbstractDatabaseLoginModule extends AbstractLoginModule
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return new JDBCUserInfo (userName, Credential.getCredential(dbCredential));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<String> getRoles (String userName)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
List<String> roles = new ArrayList<String>();
|
||||||
|
|
||||||
|
try (Connection connection = getConnection())
|
||||||
|
{
|
||||||
//query for role names
|
//query for role names
|
||||||
List<String> roles = new ArrayList<String>();
|
|
||||||
try (PreparedStatement statement = connection.prepareStatement (rolesQuery))
|
try (PreparedStatement statement = connection.prepareStatement (rolesQuery))
|
||||||
{
|
{
|
||||||
statement.setString (1, userName);
|
statement.setString (1, userName);
|
||||||
|
@ -107,11 +138,14 @@ public abstract class AbstractDatabaseLoginModule extends AbstractLoginModule
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new UserInfo (userName, Credential.getCredential(dbCredential), roles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void initialize(Subject subject,
|
public void initialize(Subject subject,
|
||||||
CallbackHandler callbackHandler,
|
CallbackHandler callbackHandler,
|
||||||
Map<String,?> sharedState,
|
Map<String,?> sharedState,
|
||||||
|
|
|
@ -54,6 +54,12 @@ public abstract class AbstractLoginModule implements LoginModule
|
||||||
private JAASUserInfo currentUser;
|
private JAASUserInfo currentUser;
|
||||||
private Subject subject;
|
private Subject subject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JAASUserInfo
|
||||||
|
*
|
||||||
|
* This class unites the UserInfo data with jaas concepts
|
||||||
|
* such as Subject and Principals
|
||||||
|
*/
|
||||||
public class JAASUserInfo
|
public class JAASUserInfo
|
||||||
{
|
{
|
||||||
private UserInfo user;
|
private UserInfo user;
|
||||||
|
@ -62,7 +68,8 @@ public abstract class AbstractLoginModule implements LoginModule
|
||||||
|
|
||||||
public JAASUserInfo (UserInfo u)
|
public JAASUserInfo (UserInfo u)
|
||||||
{
|
{
|
||||||
setUserInfo(u);
|
this.user = u;
|
||||||
|
this.principal = new JAASPrincipal(u.getUserName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUserName ()
|
public String getUserName ()
|
||||||
|
@ -75,18 +82,6 @@ public abstract class AbstractLoginModule implements LoginModule
|
||||||
return this.principal;
|
return this.principal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUserInfo (UserInfo u)
|
|
||||||
{
|
|
||||||
this.user = u;
|
|
||||||
this.principal = new JAASPrincipal(u.getUserName());
|
|
||||||
this.roles = new ArrayList<JAASRole>();
|
|
||||||
if (u.getRoleNames() != null)
|
|
||||||
{
|
|
||||||
Iterator<String> itor = u.getRoleNames().iterator();
|
|
||||||
while (itor.hasNext())
|
|
||||||
this.roles.add(new JAASRole((String)itor.next()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setJAASInfo (Subject subject)
|
public void setJAASInfo (Subject subject)
|
||||||
{
|
{
|
||||||
|
@ -106,6 +101,18 @@ public abstract class AbstractLoginModule implements LoginModule
|
||||||
{
|
{
|
||||||
return this.user.checkCredential(suppliedCredential);
|
return this.user.checkCredential(suppliedCredential);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void fetchRoles() throws Exception
|
||||||
|
{
|
||||||
|
this.user.fetchRoles();
|
||||||
|
this.roles = new ArrayList<JAASRole>();
|
||||||
|
if (this.user.getRoleNames() != null)
|
||||||
|
{
|
||||||
|
Iterator<String> itor = this.user.getRoleNames().iterator();
|
||||||
|
while (itor.hasNext())
|
||||||
|
this.roles.add(new JAASRole((String)itor.next()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Subject getSubject ()
|
public Subject getSubject ()
|
||||||
|
@ -174,7 +181,6 @@ public abstract class AbstractLoginModule implements LoginModule
|
||||||
*/
|
*/
|
||||||
public boolean commit() throws LoginException
|
public boolean commit() throws LoginException
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!isAuthenticated())
|
if (!isAuthenticated())
|
||||||
{
|
{
|
||||||
currentUser = null;
|
currentUser = null;
|
||||||
|
@ -252,7 +258,10 @@ public abstract class AbstractLoginModule implements LoginModule
|
||||||
setAuthenticated(currentUser.checkCredential(webCredential));
|
setAuthenticated(currentUser.checkCredential(webCredential));
|
||||||
|
|
||||||
if (isAuthenticated())
|
if (isAuthenticated())
|
||||||
|
{
|
||||||
|
currentUser.fetchRoles();
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
throw new FailedLoginException();
|
throw new FailedLoginException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,6 +176,28 @@ public class LdapLoginModule extends AbstractLoginModule
|
||||||
|
|
||||||
private DirContext _rootContext;
|
private DirContext _rootContext;
|
||||||
|
|
||||||
|
|
||||||
|
public class LDAPUserInfo extends UserInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param userName
|
||||||
|
* @param credential
|
||||||
|
*/
|
||||||
|
public LDAPUserInfo(String userName, Credential credential)
|
||||||
|
{
|
||||||
|
super(userName, credential);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> doFetchRoles() throws Exception
|
||||||
|
{
|
||||||
|
return getUserRoles(_rootContext, getUserName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the available information about the user
|
* get the available information about the user
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -199,9 +221,7 @@ public class LdapLoginModule extends AbstractLoginModule
|
||||||
|
|
||||||
pwdCredential = convertCredentialLdapToJetty(pwdCredential);
|
pwdCredential = convertCredentialLdapToJetty(pwdCredential);
|
||||||
Credential credential = Credential.getCredential(pwdCredential);
|
Credential credential = Credential.getCredential(pwdCredential);
|
||||||
List<String> roles = getUserRoles(_rootContext, username);
|
return new LDAPUserInfo(username, credential);
|
||||||
|
|
||||||
return new UserInfo(username, credential, roles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String doRFC2254Encoding(String inputString)
|
protected String doRFC2254Encoding(String inputString)
|
||||||
|
@ -411,12 +431,17 @@ public class LdapLoginModule extends AbstractLoginModule
|
||||||
|
|
||||||
setCurrentUser(new JAASUserInfo(userInfo));
|
setCurrentUser(new JAASUserInfo(userInfo));
|
||||||
|
|
||||||
|
boolean authed = false;
|
||||||
if (webCredential instanceof String)
|
if (webCredential instanceof String)
|
||||||
{
|
authed = credentialLogin(Credential.getCredential((String) webCredential));
|
||||||
return credentialLogin(Credential.getCredential((String) webCredential));
|
else
|
||||||
}
|
authed = credentialLogin(webCredential);
|
||||||
|
|
||||||
return credentialLogin(webCredential);
|
//only fetch roles if authenticated
|
||||||
|
if (authed)
|
||||||
|
getCurrentUser().fetchRoles();
|
||||||
|
|
||||||
|
return authed;
|
||||||
}
|
}
|
||||||
catch (UnsupportedCallbackException e)
|
catch (UnsupportedCallbackException e)
|
||||||
{
|
{
|
||||||
|
@ -496,16 +521,18 @@ public class LdapLoginModule extends AbstractLoginModule
|
||||||
|
|
||||||
String filter = "(&(objectClass={0})({1}={2}))";
|
String filter = "(&(objectClass={0})({1}={2}))";
|
||||||
|
|
||||||
LOG.info("Searching for users with filter: \'" + filter + "\'" + " from base dn: " + _userBaseDn);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Searching for users with filter: \'" + filter + "\'" + " from base dn: " + _userBaseDn);
|
||||||
|
|
||||||
Object[] filterArguments = new Object[]{
|
Object[] filterArguments = new Object[]{
|
||||||
_userObjectClass,
|
_userObjectClass,
|
||||||
_userIdAttribute,
|
_userIdAttribute,
|
||||||
username
|
username
|
||||||
};
|
};
|
||||||
NamingEnumeration<SearchResult> results = _rootContext.search(_userBaseDn, filter, filterArguments, ctls);
|
NamingEnumeration<SearchResult> results = _rootContext.search(_userBaseDn, filter, filterArguments, ctls);
|
||||||
|
|
||||||
LOG.info("Found user?: " + results.hasMoreElements());
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Found user?: " + results.hasMoreElements());
|
||||||
|
|
||||||
if (!results.hasMoreElements())
|
if (!results.hasMoreElements())
|
||||||
{
|
{
|
||||||
|
|
|
@ -101,7 +101,7 @@ public class PropertyFileLoginModule extends AbstractLoginModule
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Don't implement this as we want to pre-fetch all of the users.
|
*
|
||||||
*
|
*
|
||||||
* @param userName the user name
|
* @param userName the user name
|
||||||
* @throws Exception if unable to get the user information
|
* @throws Exception if unable to get the user information
|
||||||
|
@ -117,6 +117,8 @@ public class PropertyFileLoginModule extends AbstractLoginModule
|
||||||
if (userIdentity==null)
|
if (userIdentity==null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
//TODO in future versions change the impl of PropertyUserStore so its not
|
||||||
|
//storing Subjects etc, just UserInfo
|
||||||
Set<Principal> principals = userIdentity.getSubject().getPrincipals();
|
Set<Principal> principals = userIdentity.getSubject().getPrincipals();
|
||||||
|
|
||||||
List<String> roles = new ArrayList<String>();
|
List<String> roles = new ArrayList<String>();
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package org.eclipse.jetty.jaas.spi;
|
package org.eclipse.jetty.jaas.spi;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.security.Credential;
|
import org.eclipse.jetty.util.security.Credential;
|
||||||
|
@ -29,24 +30,70 @@ import org.eclipse.jetty.util.security.Credential;
|
||||||
* This is the information read from the external source
|
* This is the information read from the external source
|
||||||
* about a user.
|
* about a user.
|
||||||
*
|
*
|
||||||
* Can be cached by a UserInfoCache implementation
|
* Can be cached.
|
||||||
*/
|
*/
|
||||||
public class UserInfo
|
public class UserInfo
|
||||||
{
|
{
|
||||||
|
|
||||||
private String _userName;
|
private String _userName;
|
||||||
private Credential _credential;
|
private Credential _credential;
|
||||||
private List<String> _roleNames;
|
protected List<String> _roleNames = new ArrayList<>();
|
||||||
|
protected boolean _rolesLoaded = false;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param userName
|
||||||
|
* @param credential
|
||||||
|
* @param roleNames
|
||||||
|
*/
|
||||||
public UserInfo (String userName, Credential credential, List<String> roleNames)
|
public UserInfo (String userName, Credential credential, List<String> roleNames)
|
||||||
{
|
{
|
||||||
_userName = userName;
|
_userName = userName;
|
||||||
_credential = credential;
|
_credential = credential;
|
||||||
_roleNames = new ArrayList<String>();
|
|
||||||
if (roleNames != null)
|
if (roleNames != null)
|
||||||
{
|
{
|
||||||
_roleNames.addAll(roleNames);
|
synchronized (_roleNames)
|
||||||
|
{
|
||||||
|
_roleNames.addAll(roleNames);
|
||||||
|
_rolesLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param userName
|
||||||
|
* @param credential
|
||||||
|
*/
|
||||||
|
public UserInfo (String userName, Credential credential)
|
||||||
|
{
|
||||||
|
this (userName, credential, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be overridden by subclasses to obtain
|
||||||
|
* role info
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public List<String> doFetchRoles ()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fetchRoles () throws Exception
|
||||||
|
{
|
||||||
|
synchronized (_roleNames)
|
||||||
|
{
|
||||||
|
if (!_rolesLoaded)
|
||||||
|
{
|
||||||
|
_roleNames.addAll(doFetchRoles());
|
||||||
|
_rolesLoaded = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +104,7 @@ public class UserInfo
|
||||||
|
|
||||||
public List<String> getRoleNames ()
|
public List<String> getRoleNames ()
|
||||||
{
|
{
|
||||||
return new ArrayList<String>(_roleNames);
|
return Collections.unmodifiableList(_roleNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkCredential (Object suppliedCredential)
|
public boolean checkCredential (Object suppliedCredential)
|
||||||
|
|
|
@ -74,6 +74,33 @@ public class DataSourceLoginService extends MappedLoginService
|
||||||
private String _roleSql;
|
private String _roleSql;
|
||||||
private boolean _createTables = false;
|
private boolean _createTables = false;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DBUser
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DBUser extends KnownUser
|
||||||
|
{
|
||||||
|
private int _key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name
|
||||||
|
* @param credential
|
||||||
|
*/
|
||||||
|
public DBUser(String name, Credential credential, int key)
|
||||||
|
{
|
||||||
|
super(name, credential);
|
||||||
|
_key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKey ()
|
||||||
|
{
|
||||||
|
return _key;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public DataSourceLoginService()
|
public DataSourceLoginService()
|
||||||
{
|
{
|
||||||
|
@ -290,13 +317,13 @@ public class DataSourceLoginService extends MappedLoginService
|
||||||
*
|
*
|
||||||
* @param userName the user name
|
* @param userName the user name
|
||||||
*/
|
*/
|
||||||
@Override
|
@Deprecated
|
||||||
protected UserIdentity loadUser (String userName)
|
protected UserIdentity loadUser (String userName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
try (Connection connection = getConnection();
|
try (Connection connection = getConnection();
|
||||||
PreparedStatement statement1 = connection.prepareStatement(_userSql))
|
PreparedStatement statement1 = connection.prepareStatement(_userSql))
|
||||||
{
|
{
|
||||||
statement1.setObject(1, userName);
|
statement1.setObject(1, userName);
|
||||||
try (ResultSet rs1 = statement1.executeQuery())
|
try (ResultSet rs1 = statement1.executeQuery())
|
||||||
|
@ -305,19 +332,20 @@ 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);
|
||||||
List<String> roles = new ArrayList<String>();
|
|
||||||
try (PreparedStatement statement2 = connection.prepareStatement(_roleSql))
|
List<String> roles = new ArrayList<String>();
|
||||||
{
|
try (PreparedStatement statement2 = connection.prepareStatement(_roleSql))
|
||||||
statement2.setInt(1, key);
|
|
||||||
try (ResultSet rs2 = statement2.executeQuery())
|
|
||||||
{
|
{
|
||||||
while (rs2.next())
|
statement2.setInt(1, key);
|
||||||
|
try (ResultSet rs2 = statement2.executeQuery())
|
||||||
{
|
{
|
||||||
roles.add(rs2.getString(_roleTableRoleField));
|
while (rs2.next())
|
||||||
|
{
|
||||||
|
roles.add(rs2.getString(_roleTableRoleField));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return putUser(userName, Credential.getCredential(credentials), roles.toArray(new String[roles.size()]));
|
||||||
return putUser(userName, Credential.getCredential(credentials), roles.toArray(new String[roles.size()]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -334,6 +362,83 @@ public class DataSourceLoginService extends MappedLoginService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.MappedLoginService#loadUserInfo(java.lang.String)
|
||||||
|
* @Override
|
||||||
|
*/
|
||||||
|
public KnownUser loadUserInfo (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);
|
||||||
|
|
||||||
|
return new DBUser(username, Credential.getCredential(credentials), key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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#loadRoleInfo(org.eclipse.jetty.security.MappedLoginService.KnownUser)
|
||||||
|
* @Override
|
||||||
|
*/
|
||||||
|
public String[] loadRoleInfo (KnownUser user)
|
||||||
|
{
|
||||||
|
DBUser dbuser = (DBUser)user;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
try (Connection connection = getConnection();
|
||||||
|
PreparedStatement statement2 = connection.prepareStatement(_roleSql))
|
||||||
|
{
|
||||||
|
|
||||||
|
List<String> roles = new ArrayList<String>();
|
||||||
|
|
||||||
|
statement2.setInt(1, dbuser.getKey());
|
||||||
|
try (ResultSet rs2 = statement2.executeQuery())
|
||||||
|
{
|
||||||
|
while (rs2.next())
|
||||||
|
{
|
||||||
|
roles.add(rs2.getString(_roleTableRoleField));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 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 "+user.getName(), e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,7 +19,11 @@
|
||||||
package org.eclipse.jetty.security;
|
package org.eclipse.jetty.security;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
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;
|
||||||
|
@ -55,6 +59,36 @@ public class HashLoginService extends MappedLoginService implements UserListener
|
||||||
private Scanner _scanner;
|
private Scanner _scanner;
|
||||||
private 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()
|
||||||
{
|
{
|
||||||
|
@ -163,6 +197,41 @@ public class HashLoginService extends MappedLoginService implements UserListener
|
||||||
// TODO: Consider refactoring MappedLoginService to not have to override with unused methods
|
// TODO: Consider refactoring MappedLoginService to not have to override with unused methods
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] loadRoleInfo(KnownUser user)
|
||||||
|
{
|
||||||
|
UserIdentity id = _propertyUserStore.getUserIdentity(user.getName());
|
||||||
|
if (id == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
|
||||||
|
Set<RolePrincipal> roles = id.getSubject().getPrincipals(RolePrincipal.class);
|
||||||
|
if (roles == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
for (RolePrincipal r:roles)
|
||||||
|
list.add(r.getName());
|
||||||
|
|
||||||
|
return list.toArray(new String[roles.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected KnownUser loadUserInfo(String userName)
|
||||||
|
{
|
||||||
|
UserIdentity id = _propertyUserStore.getUserIdentity(userName);
|
||||||
|
if (id != null)
|
||||||
|
{
|
||||||
|
return (KnownUser)id.getUserPrincipal();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
|
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
|
||||||
|
@ -204,9 +273,11 @@ public class HashLoginService extends MappedLoginService implements UserListener
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("update: " + userName + " Roles: " + roleArray.length);
|
LOG.debug("update: " + userName + " Roles: " + roleArray.length);
|
||||||
putUser(userName,credential,roleArray);
|
//TODO need to remove and replace the authenticated user?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
public void remove(String userName)
|
public void remove(String userName)
|
||||||
|
|
|
@ -78,6 +78,32 @@ public class JDBCLoginService extends MappedLoginService
|
||||||
protected String _roleSql;
|
protected String _roleSql;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JDBCKnownUser
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class JDBCKnownUser extends KnownUser
|
||||||
|
{
|
||||||
|
int _userKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name
|
||||||
|
* @param credential
|
||||||
|
*/
|
||||||
|
public JDBCKnownUser(String name, Credential credential, int key)
|
||||||
|
{
|
||||||
|
super(name, credential);
|
||||||
|
_userKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int getUserKey ()
|
||||||
|
{
|
||||||
|
return _userKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public JDBCLoginService()
|
public JDBCLoginService()
|
||||||
throws IOException
|
throws IOException
|
||||||
|
@ -231,7 +257,7 @@ public class JDBCLoginService extends MappedLoginService
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Deprecated
|
||||||
protected UserIdentity loadUser(String username)
|
protected UserIdentity loadUser(String username)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -251,6 +277,8 @@ 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);
|
||||||
|
|
||||||
|
|
||||||
List<String> roles = new ArrayList<String>();
|
List<String> roles = new ArrayList<String>();
|
||||||
|
|
||||||
try (PreparedStatement stat2 = _con.prepareStatement(_roleSql))
|
try (PreparedStatement stat2 = _con.prepareStatement(_roleSql))
|
||||||
|
@ -262,7 +290,7 @@ public class JDBCLoginService extends MappedLoginService
|
||||||
roles.add(rs2.getString(_roleTableRoleField));
|
roles.add(rs2.getString(_roleTableRoleField));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return putUser(username, credentials, roles.toArray(new String[roles.size()]));
|
return putUser(username, Credential.getCredential(credentials), roles.toArray(new String[roles.size()]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,13 +303,89 @@ public class JDBCLoginService extends MappedLoginService
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
protected UserIdentity putUser (String username, String credentials, String[] roles)
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.MappedLoginService#loadUserInfo(java.lang.String)
|
||||||
|
* @Override
|
||||||
|
*/
|
||||||
|
public KnownUser loadUserInfo (String username)
|
||||||
{
|
{
|
||||||
return putUser(username, Credential.getCredential(credentials),roles);
|
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);
|
||||||
|
|
||||||
|
return new JDBCKnownUser (username, Credential.getCredential(credentials), key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SQLException e)
|
||||||
|
{
|
||||||
|
LOG.warn("UserRealm " + getName() + " could not load user information from database", e);
|
||||||
|
closeConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.security.MappedLoginService#loadRoleInfo(org.eclipse.jetty.security.MappedLoginService.KnownUser)
|
||||||
|
* @Override
|
||||||
|
*/
|
||||||
|
public String[] loadRoleInfo (KnownUser user)
|
||||||
|
{
|
||||||
|
JDBCKnownUser jdbcUser = (JDBCKnownUser)user;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (null == _con)
|
||||||
|
connectDatabase();
|
||||||
|
|
||||||
|
if (null == _con)
|
||||||
|
throw new SQLException("Can't connect to database");
|
||||||
|
|
||||||
|
|
||||||
|
List<String> roles = new ArrayList<String>();
|
||||||
|
|
||||||
|
try (PreparedStatement stat2 = _con.prepareStatement(_roleSql))
|
||||||
|
{
|
||||||
|
stat2.setInt(1, jdbcUser.getUserKey());
|
||||||
|
try (ResultSet rs2 = stat2.executeQuery())
|
||||||
|
{
|
||||||
|
while (rs2.next())
|
||||||
|
roles.add(rs2.getString(_roleTableRoleField));
|
||||||
|
return roles.toArray(new String[roles.size()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SQLException e)
|
||||||
|
{
|
||||||
|
LOG.warn("UserRealm " + getName() + " could not load user information from database", e);
|
||||||
|
closeConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close an existing connection
|
* Close an existing connection
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -139,6 +139,8 @@ public abstract class MappedLoginService extends AbstractLifeCycle implements Lo
|
||||||
public void logout(UserIdentity identity)
|
public void logout(UserIdentity identity)
|
||||||
{
|
{
|
||||||
LOG.debug("logout {}",identity);
|
LOG.debug("logout {}",identity);
|
||||||
|
|
||||||
|
//TODO should remove the user?????
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -201,6 +203,24 @@ public abstract class MappedLoginService extends AbstractLifeCycle implements Lo
|
||||||
return 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)
|
public void removeUser(String username)
|
||||||
{
|
{
|
||||||
|
@ -219,9 +239,17 @@ public abstract class MappedLoginService extends AbstractLifeCycle implements Lo
|
||||||
UserIdentity user = _users.get(username);
|
UserIdentity user = _users.get(username);
|
||||||
|
|
||||||
if (user==null)
|
if (user==null)
|
||||||
user = loadUser(username);
|
{
|
||||||
|
KnownUser userPrincipal = loadUserInfo(username);
|
||||||
if (user!=null)
|
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();
|
UserPrincipal principal = (UserPrincipal)user.getUserPrincipal();
|
||||||
if (principal.authenticate(credentials))
|
if (principal.authenticate(credentials))
|
||||||
|
@ -241,7 +269,10 @@ public abstract class MappedLoginService extends AbstractLifeCycle implements Lo
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
protected abstract String[] loadRoleInfo (KnownUser user);
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
protected abstract KnownUser loadUserInfo (String username);
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
protected abstract UserIdentity loadUser(String username);
|
protected abstract UserIdentity loadUser(String username);
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,13 @@
|
||||||
</securityHandler>
|
</securityHandler>
|
||||||
</webAppConfig>
|
</webAppConfig>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>5.1.19</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
xyz {
|
xyz {
|
||||||
org.eclipse.jetty.jaas.spi.PropertyFileLoginModule required
|
org.eclipse.jetty.jaas.spi.JDBCLoginModule required
|
||||||
debug="true"
|
debug="true"
|
||||||
file="${jetty.base}/etc/login.properties";
|
userTable="users"
|
||||||
|
userField="username"
|
||||||
|
credentialField="pwd"
|
||||||
|
userRoleTable="userroles"
|
||||||
|
userRoleUserField="username"
|
||||||
|
userRoleRoleField="rolename"
|
||||||
|
dbDriver="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource"
|
||||||
|
dbUrl="jdbc:mysql://localhost:3306/jaas"
|
||||||
|
dbUserName="janb";
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue