Index: lams_build/build.xml
===================================================================
diff -u -r5661c79b661c18221c0eb5e32fe7ec54110e5a65 -r665bafc925d571fea2e089e161a7d164d73c96bd
--- lams_build/build.xml (.../build.xml) (revision 5661c79b661c18221c0eb5e32fe7ec54110e5a65)
+++ lams_build/build.xml (.../build.xml) (revision 665bafc925d571fea2e089e161a7d164d73c96bd)
@@ -650,7 +650,7 @@
+ file="lib/micrometer/micrometer.module.xml" overwrite="true" verbose="true" />
@@ -742,8 +742,33 @@
-
+
+
+ ${ant.project.name}: Deploying custom Elytron security module
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
${ant.project.name}: Deploying configuration files
Index: lams_build/build_base.xml
===================================================================
diff -u -r1c8910051a18a9f9069876c35bd35ccad81e3955 -r665bafc925d571fea2e089e161a7d164d73c96bd
--- lams_build/build_base.xml (.../build_base.xml) (revision 1c8910051a18a9f9069876c35bd35ccad81e3955)
+++ lams_build/build_base.xml (.../build_base.xml) (revision 665bafc925d571fea2e089e161a7d164d73c96bd)
@@ -37,7 +37,6 @@
-
@@ -62,6 +61,8 @@
+
+
Index: lams_build/conf/standalone.xml
===================================================================
diff -u -r08c6a122c4ad83bf970409c0875bd1768d205c92 -r665bafc925d571fea2e089e161a7d164d73c96bd
--- lams_build/conf/standalone.xml (.../standalone.xml) (revision 08c6a122c4ad83bf970409c0875bd1768d205c92)
+++ lams_build/conf/standalone.xml (.../standalone.xml) (revision 665bafc925d571fea2e089e161a7d164d73c96bd)
@@ -335,9 +335,10 @@
+
-
+
@@ -362,8 +363,8 @@
-
-
+
+
@@ -376,7 +377,12 @@
-
+
+
+
+
+
+
@@ -608,7 +614,7 @@
-
+
Index: lams_build/lib/elytron/elytron.module.xml
===================================================================
diff -u
--- lams_build/lib/elytron/elytron.module.xml (revision 0)
+++ lams_build/lib/elytron/elytron.module.xml (revision 665bafc925d571fea2e089e161a7d164d73c96bd)
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
Index: lams_central/.classpath
===================================================================
diff -u -r5e9e3c6915701ed7a340d47ff6d32c12ccb9e800 -r665bafc925d571fea2e089e161a7d164d73c96bd
--- lams_central/.classpath (.../.classpath) (revision 5e9e3c6915701ed7a340d47ff6d32c12ccb9e800)
+++ lams_central/.classpath (.../.classpath) (revision 665bafc925d571fea2e089e161a7d164d73c96bd)
@@ -38,6 +38,8 @@
+
+
Index: lams_central/build.xml
===================================================================
diff -u -r924d4186e55122ce91b5dcaba3311ab026060e94 -r665bafc925d571fea2e089e161a7d164d73c96bd
--- lams_central/build.xml (.../build.xml) (revision 924d4186e55122ce91b5dcaba3311ab026060e94)
+++ lams_central/build.xml (.../build.xml) (revision 665bafc925d571fea2e089e161a7d164d73c96bd)
@@ -79,12 +79,16 @@
-
+
+
+
+
+
-
\ No newline at end of file
Index: lams_central/src/java/org/lamsfoundation/lams/security/DatabaseAuthenticator.java
===================================================================
diff -u -rcb01d2d8c064728cb0e2ac524d2f89622a534e39 -r665bafc925d571fea2e089e161a7d164d73c96bd
--- lams_central/src/java/org/lamsfoundation/lams/security/DatabaseAuthenticator.java (.../DatabaseAuthenticator.java) (revision cb01d2d8c064728cb0e2ac524d2f89622a534e39)
+++ lams_central/src/java/org/lamsfoundation/lams/security/DatabaseAuthenticator.java (.../DatabaseAuthenticator.java) (revision 665bafc925d571fea2e089e161a7d164d73c96bd)
@@ -33,7 +33,8 @@
import javax.sql.DataSource;
import org.apache.commons.lang3.StringUtils;
-import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.LogManager;
import org.lamsfoundation.lams.util.HashUtil;
/**
Index: lams_central/src/java/org/lamsfoundation/lams/security/RealmIdentity.java
===================================================================
diff -u -r08c6a122c4ad83bf970409c0875bd1768d205c92 -r665bafc925d571fea2e089e161a7d164d73c96bd
--- lams_central/src/java/org/lamsfoundation/lams/security/RealmIdentity.java (.../RealmIdentity.java) (revision 08c6a122c4ad83bf970409c0875bd1768d205c92)
+++ lams_central/src/java/org/lamsfoundation/lams/security/RealmIdentity.java (.../RealmIdentity.java) (revision 665bafc925d571fea2e089e161a7d164d73c96bd)
@@ -11,18 +11,16 @@
import java.security.Principal;
import java.security.spec.AlgorithmParameterSpec;
-import java.util.Arrays;
import java.util.Set;
+/**
+ * Custom Elytron realm identity. It delegates authentication and authorisation to UniversalLoginModule.
+ */
public class RealmIdentity implements org.wildfly.security.auth.server.RealmIdentity {
private final Principal principal;
- private final String password;
- private final Set roles;
- public RealmIdentity(Principal principal, String password, Set roles) {
+ public RealmIdentity(Principal principal) {
this.principal = principal;
- this.password = password;
- this.roles = roles;
}
@Override
@@ -32,20 +30,17 @@
@Override
public SupportLevel getCredentialAcquireSupport(Class extends Credential> credentialType, String algorithmName,
- AlgorithmParameterSpec parameterSpec) throws RealmUnavailableException {
- // do not support credential acquire
+ AlgorithmParameterSpec parameterSpec) {
return SupportLevel.UNSUPPORTED;
}
@Override
- public C getCredential(Class credentialType) throws RealmUnavailableException {
- // do not return credentials
+ public C getCredential(Class credentialType) {
return null;
}
@Override
- public SupportLevel getEvidenceVerifySupport(Class extends Evidence> evidenceType, String algorithmName)
- throws RealmUnavailableException {
+ public SupportLevel getEvidenceVerifySupport(Class extends Evidence> evidenceType, String algorithmName) {
return PasswordGuessEvidence.class.isAssignableFrom(evidenceType)
? SupportLevel.SUPPORTED
: SupportLevel.UNSUPPORTED;
@@ -55,7 +50,7 @@
public boolean verifyEvidence(Evidence evidence) throws RealmUnavailableException {
if (evidence instanceof PasswordGuessEvidence) {
PasswordGuessEvidence guess = (PasswordGuessEvidence) evidence;
- return Arrays.equals(password.toCharArray(), guess.getGuess());
+ return UniversalLoginModule.validatePassword(principal.getName(), String.valueOf(guess.getGuess()));
}
return false;
}
@@ -67,6 +62,7 @@
@Override
public Attributes getAttributes() throws RealmUnavailableException {
+ Set roles = UniversalLoginModule.getRoles(principal.getName());
if (roles == null || roles.isEmpty()) {
return Attributes.EMPTY;
}
Index: lams_central/src/java/org/lamsfoundation/lams/security/SecurityRealm.java
===================================================================
diff -u -r08c6a122c4ad83bf970409c0875bd1768d205c92 -r665bafc925d571fea2e089e161a7d164d73c96bd
--- lams_central/src/java/org/lamsfoundation/lams/security/SecurityRealm.java (.../SecurityRealm.java) (revision 08c6a122c4ad83bf970409c0875bd1768d205c92)
+++ lams_central/src/java/org/lamsfoundation/lams/security/SecurityRealm.java (.../SecurityRealm.java) (revision 665bafc925d571fea2e089e161a7d164d73c96bd)
@@ -1,60 +1,44 @@
package org.lamsfoundation.lams.security;
-import org.wildfly.security.credential.Credential;
import org.wildfly.security.auth.SupportLevel;
-import org.wildfly.security.auth.realm.CacheableSecurityRealm;
+import org.wildfly.security.auth.server.RealmIdentity;
import org.wildfly.security.auth.server.RealmUnavailableException;
+import org.wildfly.security.credential.Credential;
import org.wildfly.security.evidence.Evidence;
import org.wildfly.security.evidence.PasswordGuessEvidence;
-import org.wildfly.security.auth.server.RealmIdentity;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.security.Principal;
import java.security.spec.AlgorithmParameterSpec;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-public class SecurityRealm implements CacheableSecurityRealm {
+/**
+ * Custom Elytron security realm.
+ * It is deployed in a JAR as WildFly org.lamsfoundation.lams.security module.
+ */
+public class SecurityRealm implements org.wildfly.security.auth.server.SecurityRealm {
+ protected String dsJndiName;
+ protected String loginModuleJndiName;
+ protected Object loginModule;
- private Map users;
- private Map> roles;
-
- public SecurityRealm() {
- // nothing
+ /**
+ * Initialise the realm with the configuration. It gets run by WildFly on startup. It is filled with configuration
+ * from standalone.xml.
+ */
+ public void initialize(final Map configuration) {
+ dsJndiName = configuration.get("dsJndiName");
+ loginModuleJndiName = configuration.get("loginModuleJndiName");
}
- public SecurityRealm(Map map) {
- // test
- initialize(map);
- }
+ // If we make this Security Realm implement CacheableSecurityRealm, we need to implement this method.
+ // @Override
+ // public void registerIdentityChangeListener(Consumer cnsmr) {
+ // }
- public void initialize(Map map) {
- users = new HashMap<>();
- roles = new HashMap<>();
- //Adding Guest users
- String guest[] = new String[] { "Guest" };
- for (Map.Entry entry : map.entrySet()) {
- // user and password
- users.put(entry.getKey(), entry.getValue());
- roles.put(entry.getKey(), new HashSet(Arrays.asList(guest)));
- }
- // Adding other users
- String array[] = new String[] { "SYSADMIN", "AUTHOR" };
- users.put("test1", "test1");
- roles.put("test1", new HashSet(Arrays.asList(array)));
- System.out.println("I've loaded " + users.size() + " users ");
- }
-
@Override
- public void registerIdentityChangeListener(Consumer cnsmr) {
- // nothing
- }
-
- @Override
public SupportLevel getCredentialAcquireSupport(Class extends Credential> credentialType, String algorithmName,
AlgorithmParameterSpec parameterSpec) throws RealmUnavailableException {
return SupportLevel.UNSUPPORTED;
@@ -69,19 +53,32 @@
}
@Override
- public RealmIdentity getRealmIdentity(final Principal principal) throws RealmUnavailableException {
- // just search the user in the configured users
- String password = users.get(principal.getName());
- if (password != null) {
- return new org.lamsfoundation.lams.security.RealmIdentity(principal, password,
- roles.get(principal.getName()));
+ public RealmIdentity getRealmIdentity(Principal principal) throws RealmUnavailableException {
+ if (loginModule == null) {
+ // Obtain UniversalLoginModule as EJB3 from JNDI
+ // We can not use UniversalLoginModule directly
+ // as this class needs to be independent on LAMS code.
+ try {
+ Context context = new javax.naming.InitialContext();
+ loginModule = context.lookup(loginModuleJndiName);
+ if (loginModule == null) {
+ throw new RealmUnavailableException("Could not find login module");
+ }
+ // pass configuration to login module
+ Method method = loginModule.getClass().getMethod("setDsJndiName", String.class);
+ method.invoke(loginModule, dsJndiName);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | NamingException e) {
+ e.printStackTrace();
+ throw new RealmUnavailableException("Could not fetch login module", e);
+ }
}
- return RealmIdentity.NON_EXISTENT;
- }
- @Override
- public String toString() {
- return "SecurityRealm: " + this.users.keySet().stream().collect(Collectors.toList());
+ try {
+ Method method = loginModule.getClass().getMethod("getRealmIdentity", Principal.class);
+ RealmIdentity realmIdentity = (RealmIdentity) method.invoke(loginModule, principal);
+ return realmIdentity == null ? RealmIdentity.NON_EXISTENT : realmIdentity;
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ throw new RealmUnavailableException("Could not authenticate", e);
+ }
}
-
}
\ No newline at end of file
Fisheye: Tag 665bafc925d571fea2e089e161a7d164d73c96bd refers to a dead (removed) revision in file `lams_central/src/java/org/lamsfoundation/lams/security/SimpleGroup.java'.
Fisheye: No comparison available. Pass `N' to diff?
Fisheye: Tag 665bafc925d571fea2e089e161a7d164d73c96bd refers to a dead (removed) revision in file `lams_central/src/java/org/lamsfoundation/lams/security/SimplePrincipal.java'.
Fisheye: No comparison available. Pass `N' to diff?
Index: lams_central/src/java/org/lamsfoundation/lams/security/UniversalLoginModule.java
===================================================================
diff -u -rcb01d2d8c064728cb0e2ac524d2f89622a534e39 -r665bafc925d571fea2e089e161a7d164d73c96bd
--- lams_central/src/java/org/lamsfoundation/lams/security/UniversalLoginModule.java (.../UniversalLoginModule.java) (revision cb01d2d8c064728cb0e2ac524d2f89622a534e39)
+++ lams_central/src/java/org/lamsfoundation/lams/security/UniversalLoginModule.java (.../UniversalLoginModule.java) (revision 665bafc925d571fea2e089e161a7d164d73c96bd)
@@ -22,36 +22,9 @@
*/
package org.lamsfoundation.lams.security;
-import java.io.IOException;
-import java.security.Principal;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-import javax.security.auth.Subject;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-import javax.security.auth.login.FailedLoginException;
-import javax.security.auth.login.LoginException;
-import javax.security.auth.spi.LoginModule;
-import javax.sql.DataSource;
-
import org.apache.commons.lang3.StringUtils;
-import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
-import org.lamsfoundation.lams.themes.Theme;
+import org.apache.logging.log4j.Logger;
import org.lamsfoundation.lams.themes.dto.ThemeDTO;
import org.lamsfoundation.lams.themes.service.IThemeService;
import org.lamsfoundation.lams.usermanagement.AuthenticationMethodType;
@@ -68,22 +41,27 @@
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
+import org.wildfly.security.auth.server.RealmUnavailableException;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.sql.DataSource;
+import java.security.Principal;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
/**
- * Covers all LAMS authentication.
+ * Covers all LAMS authentication. It is fetched by org.lamsfoundation.lams.security.SecurityRealm as EJB3 from JNDI.
*/
-public class UniversalLoginModule implements LoginModule {
+public class UniversalLoginModule {
private static Logger log = LogManager.getLogger(UniversalLoginModule.class);
- private Subject subject;
- private CallbackHandler callbackHandler;
- /**
- * Flag indicating if the login 1st phase succeeded.
- */
- private boolean loginOK;
- private Principal identity;
- private char[] credential;
-
private static String dsJndiName;
private static final Map internalAuthenticationTokens = new TreeMap<>();
@@ -92,187 +70,43 @@
private static IUserManagementService userManagementService;
private static final long INTERNAL_AUTHENTICATION_TIMEOUT = 60 * 1000;
- private static final String ROLES_QUERY = "SELECT DISTINCT r.name,'Roles' FROM lams_user u "
- + "LEFT OUTER JOIN lams_user_organisation uo USING(user_id) "
- + "LEFT OUTER JOIN lams_user_organisation_role urr USING(user_organisation_id) "
- + "LEFT OUTER JOIN lams_role r USING (role_id) " + "WHERE u.login=?";
+ private static final String ROLES_QUERY =
+ "SELECT DISTINCT r.name FROM lams_user u " + "LEFT OUTER JOIN lams_user_organisation uo USING(user_id) "
+ + "LEFT OUTER JOIN lams_user_organisation_role urr USING(user_organisation_id) "
+ + "LEFT OUTER JOIN lams_role r USING (role_id) WHERE u.login=?";
/**
- * Method to commit the authentication process (phase 2).
+ * Set the JNDI name of the datasource. It is called by org.lamsfoundation.lams.security.SecurityRealm using
+ * reflection.
*/
- @Override
- public boolean commit() throws LoginException {
- if (!loginOK) {
- return false;
- }
+ public void setDsJndiName(String dsJndiName) {
+ UniversalLoginModule.dsJndiName = dsJndiName;
- /*
- * If the login method completed successfully as indicated by
- * loginOK == true, this method adds the identity value to the subject's principals set. It also adds the
- * members of
- * each Group returned by getRoleSets() to the subject's principals Set.
- */
- Set principals = subject.getPrincipals();
- principals.add(identity);
- for (SimpleGroup group : getRoleSets()) {
- String name = group.getName();
- SimpleGroup subjectGroup = createGroup(name, principals);
- // Copy the group members to the Subject group
- Enumeration extends Principal> members = group.members();
- while (members.hasMoreElements()) {
- Principal role = members.nextElement();
- subjectGroup.addMember(role);
- }
- }
-
- UniversalLoginModule.log.info("User logged in: " + getUserName());
- return true;
+ // get service beans from the Spring context
+ WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(
+ SessionManager.getServletContext());
+ UniversalLoginModule.userManagementService = (IUserManagementService) ctx.getBean("userManagementService");
+ UniversalLoginModule.themeService = (IThemeService) ctx.getBean("themeService");
}
/**
- * Method to abort the authentication process (phase 2).
- *
- * @return true alaways
+ * Get the realm identity for the given principal. It is called by org.lamsfoundation.lams.security.SecurityRealm
+ * using reflection.
*/
- @Override
- public boolean abort() throws LoginException {
- UniversalLoginModule.log.info("Abort log in for user: " + getUserName());
- return true;
- }
-
- /**
- * Remove the user identity and roles added to the Subject during commit.
- *
- * @return true always.
- */
- @Override
- public boolean logout() throws LoginException {
- UniversalLoginModule.log.info("User logged out: " + getUserName());
- // Remove the user identity
- Set principals = subject.getPrincipals();
- principals.remove(identity);
- return true;
- }
-
- /**
- * Find or create a Group with the given name. Subclasses should use this method to locate the 'Roles' group or
- * create additional types of groups.
- *
- * @return A named Group from the principals set.
- */
- private SimpleGroup createGroup(String name, Set principals) {
- SimpleGroup roles = null;
- for (Principal principal : principals) {
- if (principal instanceof SimpleGroup) {
- SimpleGroup grp = (SimpleGroup) principal;
- if (grp.getName().equals(name)) {
- roles = grp;
- break;
- }
- }
+ public org.wildfly.security.auth.server.RealmIdentity getRealmIdentity(Principal principal) {
+ User user = UniversalLoginModule.userManagementService.getUserByLogin(principal.getName());
+ if (user == null) {
+ return RealmIdentity.NON_EXISTENT;
}
- // If we did not find a group create one
- if (roles == null) {
- roles = new SimpleGroup(name);
- principals.add(roles);
- }
- return roles;
+ return new RealmIdentity(principal);
}
/**
- * Perform the authentication of the username and password.
+ * Static method that does the real authentication. It is called directly by
+ * org.lamsfoundation.lams.security.RealmIdentity
*/
- @Override
- public boolean login() throws LoginException {
- loginOK = false;
- String[] info = getUsernameAndPassword();
- String userName = info[0];
- String password = info[1];
-
- UniversalLoginModule.log.info("Authenticate user: " + userName);
-
- if (identity == null) {
- try {
- identity = new SimplePrincipal(userName);
- } catch (Exception e) {
- throw new LoginException("Failed to create principal: " + e.getMessage());
- }
-
- if (!validatePassword(password)) {
- if (UniversalLoginModule.log.isDebugEnabled()) {
- UniversalLoginModule.log.info("Bad password for user: " + userName);
- }
- throw new FailedLoginException("Incorrect password");
- }
- }
-
- loginOK = true;
- if (UniversalLoginModule.log.isDebugEnabled()) {
- UniversalLoginModule.log.debug("User authenticated: " + identity);
- }
- return true;
- }
-
- /**
- * Return user name from existing identity.
- */
- private String getUserName() {
- return identity == null ? null : identity.getName();
- }
-
- /**
- * Called by login() to acquire the username and password strings for authentication. This method does no validation
- * of either.
- *
- * @return String[], [0] = username, [1] = password
- */
- private String[] getUsernameAndPassword() throws LoginException {
- if (callbackHandler == null) {
- throw new LoginException("No CallbackHandler available to collect authentication information");
- }
- NameCallback nc = new NameCallback("User name: ", "guest");
- PasswordCallback pc = new PasswordCallback("Password: ", false);
- Callback[] callbacks = { nc, pc };
- String username = null;
- String password = null;
- try {
- callbackHandler.handle(callbacks);
- username = nc.getName();
- char[] tmpPassword = pc.getPassword();
- if (tmpPassword != null) {
- credential = new char[tmpPassword.length];
- System.arraycopy(tmpPassword, 0, credential, 0, tmpPassword.length);
- pc.clearPassword();
- password = new String(credential);
- }
- } catch (IOException ioe) {
- throw new LoginException(ioe.toString());
- } catch (UnsupportedCallbackException uce) {
- throw new LoginException("CallbackHandler does not support: " + uce.getCallback());
- }
- return new String[] { username, password };
- }
-
- @Override
- public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState,
- Map options) {
- this.subject = subject;
- this.callbackHandler = callbackHandler;
-
- if (UniversalLoginModule.dsJndiName == null) {
- UniversalLoginModule.dsJndiName = (String) options.get("dsJndiName");
- }
- }
-
- private boolean validatePassword(String inputPassword) {
- WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(
- SessionManager.getServletContext());
- if (UniversalLoginModule.userManagementService == null) {
- UniversalLoginModule.userManagementService = (IUserManagementService) ctx.getBean("userManagementService");
- UniversalLoginModule.themeService = (IThemeService) ctx.getBean("themeService");
- }
-
+ public static boolean validatePassword(String userName, String inputPassword) {
// there is no session if the request did not go through SsoHandler
// it happens on session failover
if (SessionManager.getSession() != null) {
@@ -286,8 +120,6 @@
}
}
- String userName = getUserName();
-
// empty password not allowed
if (StringUtils.isBlank(inputPassword)) {
if (UniversalLoginModule.log.isDebugEnabled()) {
@@ -326,6 +158,8 @@
// provision a new user by checking LDAP server
LdapService ldapService = null;
try {
+ WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(
+ SessionManager.getServletContext());
ldapService = (LdapService) ctx.getBean("ldapService");
} catch (NoSuchBeanDefinitionException e) {
// LDEV-1937
@@ -417,108 +251,55 @@
}
/**
- * According to Lams's security policy, all the authorization must be done locally, in other word, through Lams
- * database or other "local"(logically) data resource.
- *
- * @return Group[] containing the sets of roles
+ * Static method that does the real authorisation. It is called directly by
+ * org.lamsfoundation.lams.security.RealmIdentity
*/
- private SimpleGroup[] getRoleSets() throws LoginException {
- String userName = getUserName();
- Map setsMap = new HashMap<>();
- Connection conn = null;
- PreparedStatement ps = null;
- ResultSet rs = null;
+ public static Set getRoles(String userName) throws RealmUnavailableException {
+ Set roles = new HashSet<>();
try {
-
InitialContext ctx = new InitialContext();
- DataSource ds = (DataSource) ctx.lookup(UniversalLoginModule.dsJndiName);
+ DataSource ds = (DataSource) ctx.lookup(dsJndiName);
- conn = ds.getConnection();
- // Get the user role names
- ps = conn.prepareStatement(UniversalLoginModule.ROLES_QUERY);
- ps.setString(1, userName);
- rs = ps.executeQuery();
- if (!rs.next()) {
- throw new FailedLoginException("No matching user name found in roles: " + userName);
- }
-
- ArrayList groupMembers = new ArrayList<>();
- do {
- String name = rs.getString(1);
- String groupName = rs.getString(2);
- if ((groupName == null) || (groupName.length() == 0)) {
- groupName = "Roles";
+ try (Connection conn = ds.getConnection();
+ PreparedStatement ps = conn.prepareStatement(UniversalLoginModule.ROLES_QUERY)) {
+ // Get the user role names
+ ps.setString(1, userName);
+ ResultSet rs = ps.executeQuery();
+ if (!rs.next()) {
+ log.warn("No matching user name found in roles: " + userName);
+ return null;
}
- SimpleGroup group = setsMap.get(groupName);
- if (group == null) {
- group = new SimpleGroup(groupName);
- setsMap.put(groupName, group);
- }
- try {
- Principal p = null;
+ do {
+ String name = rs.getString(1);
+
// Assign minimal role if user has none
if (name == null) {
name = Role.LEARNER;
UniversalLoginModule.log.info("Found no roles for user: " + userName + ", assigning: " + name);
}
- p = new SimplePrincipal(name);
- if (!groupMembers.contains(name)) {
- UniversalLoginModule.log.info("Assign user: " + userName + " to role " + p.getName());
- group.addMember(p);
- groupMembers.add(name);
- }
+ roles.add(name);
+
// sysadmin is always app admin
- if (name.equals(Role.SYSADMIN) && !groupMembers.contains(Role.APPADMIN)) {
+ if (name.equals(Role.SYSADMIN) && !roles.contains(Role.APPADMIN)) {
UniversalLoginModule.log.info("Assign user: " + userName + " to role " + Role.APPADMIN);
- group.addMember(p);
- groupMembers.add(Role.APPADMIN);
+ roles.add(Role.APPADMIN);
}
if (name.equals(Role.APPADMIN) || name.equals(Role.SYSADMIN)) {
- p = new SimplePrincipal(Role.AUTHOR);
UniversalLoginModule.log.info("Found role " + name);
- if (!groupMembers.contains(Role.AUTHOR)) {
+ if (!roles.contains(Role.AUTHOR)) {
UniversalLoginModule.log.info("Assign user: " + userName + " to role " + Role.AUTHOR);
- group.addMember(p);
- groupMembers.add(Role.AUTHOR);
+ roles.add(Role.AUTHOR);
}
}
- } catch (Exception e) {
- UniversalLoginModule.log.info("Failed to create principal: " + name + " for user: " + userName, e);
- }
- } while (rs.next());
- } catch (NamingException e) {
- throw new LoginException(e.toString(true));
- } catch (SQLException e) {
- throw new LoginException(e.toString());
- } finally {
- if (rs != null) {
- try {
- rs.close();
- } catch (SQLException e) {
- UniversalLoginModule.log.error(e);
- }
+
+ } while (rs.next());
}
- if (ps != null) {
- try {
- ps.close();
- } catch (SQLException e) {
- UniversalLoginModule.log.error(e);
- }
- }
- if (conn != null) {
- try {
- conn.close();
- } catch (Exception e) {
- UniversalLoginModule.log.error(e);
- }
- }
+ } catch (NamingException | SQLException e) {
+ throw new RealmUnavailableException("Error while fetching roles", e);
}
-
- SimpleGroup[] roleSets = new SimpleGroup[setsMap.size()];
- setsMap.values().toArray(roleSets);
- return roleSets;
+ return roles;
}
/**
Index: lams_central/src/java/org/lamsfoundation/lams/web/SessionListener.java
===================================================================
diff -u -r35d617e013c37361e7d89025c464a7f4a53b9b4e -r665bafc925d571fea2e089e161a7d164d73c96bd
--- lams_central/src/java/org/lamsfoundation/lams/web/SessionListener.java (.../SessionListener.java) (revision 35d617e013c37361e7d89025c464a7f4a53b9b4e)
+++ lams_central/src/java/org/lamsfoundation/lams/web/SessionListener.java (.../SessionListener.java) (revision 665bafc925d571fea2e089e161a7d164d73c96bd)
@@ -23,27 +23,19 @@
package org.lamsfoundation.lams.web;
-import java.security.Principal;
-import java.util.Locale;
-
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;
import jakarta.servlet.jsp.jstl.core.Config;
-
-import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager;
-//import org.jboss.security.CacheableManager;
-import org.lamsfoundation.lams.security.SimplePrincipal;
-import org.lamsfoundation.lams.usermanagement.dto.UserDTO;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.lamsfoundation.lams.util.Configuration;
import org.lamsfoundation.lams.util.ConfigurationKeys;
import org.lamsfoundation.lams.util.LanguageUtil;
import org.lamsfoundation.lams.web.filter.LocaleFilter;
-import org.lamsfoundation.lams.web.session.SessionManager;
-import org.lamsfoundation.lams.web.util.AttributeNames;
+import java.util.Locale;
+
/**
* Listens for creation of HTTP sessions. Sets inactive timeout and default locale.
*/
Index: lams_central/web/WEB-INF/ejb-jar.xml
===================================================================
diff -u
--- lams_central/web/WEB-INF/ejb-jar.xml (revision 0)
+++ lams_central/web/WEB-INF/ejb-jar.xml (revision 665bafc925d571fea2e089e161a7d164d73c96bd)
@@ -0,0 +1,15 @@
+
+
+
+
+ lams-login-module
+ org.lamsfoundation.lams.security.UniversalLoginModule
+ Stateless
+ Container
+
+
+
\ No newline at end of file
Index: lams_common/src/java/org/lamsfoundation/lams/integration/security/SsoHandler.java
===================================================================
diff -u -r44cc1e311b449f4af21b8153341a355b2f1820a0 -r665bafc925d571fea2e089e161a7d164d73c96bd
--- lams_common/src/java/org/lamsfoundation/lams/integration/security/SsoHandler.java (.../SsoHandler.java) (revision 44cc1e311b449f4af21b8153341a355b2f1820a0)
+++ lams_common/src/java/org/lamsfoundation/lams/integration/security/SsoHandler.java (.../SsoHandler.java) (revision 665bafc925d571fea2e089e161a7d164d73c96bd)
@@ -16,23 +16,25 @@
*/
package org.lamsfoundation.lams.integration.security;
-import java.io.IOException;
-import java.security.AccessController;
-import java.security.Principal;
-import java.util.Date;
-import java.util.StringTokenizer;
-
+import com.warrenstrange.googleauth.GoogleAuthenticator;
+import io.undertow.Handlers;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.server.session.Session;
+import io.undertow.servlet.ServletExtension;
+import io.undertow.servlet.api.DeploymentInfo;
+import io.undertow.servlet.handlers.ServletRequestContext;
+import io.undertow.servlet.spec.HttpSessionImpl;
+import io.undertow.util.Headers;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
-
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
-import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.lamsfoundation.lams.logevent.LogEvent;
import org.lamsfoundation.lams.logevent.service.ILogEventService;
import org.lamsfoundation.lams.usermanagement.User;
@@ -48,23 +50,15 @@
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
-import com.warrenstrange.googleauth.GoogleAuthenticator;
+import java.io.IOException;
+import java.security.AccessController;
+import java.util.Date;
+import java.util.StringTokenizer;
-import io.undertow.Handlers;
-import io.undertow.server.HttpServerExchange;
-import io.undertow.server.session.Session;
-import io.undertow.servlet.ServletExtension;
-import io.undertow.servlet.api.DeploymentInfo;
-import io.undertow.servlet.handlers.ServletRequestContext;
-import io.undertow.servlet.spec.HttpSessionImpl;
-import io.undertow.util.Headers;
-import org.wildfly.security.auth.server.SecurityDomain;
-
/**
* Allows access to LAMS WARs when an user logs in.
*
* @author Marcin Cieslak
- *
*/
public class SsoHandler implements ServletExtension {
private static ILogEventService logEventService = null;
@@ -293,8 +287,8 @@
/**
* Forward to the login page with a specific error message. Avoids a redirect. Based on the
- * ServletFormAuthenticationMechanism method. The location should be relative to the current
- * context and start with "/" e.g. /login.jsp
+ * ServletFormAuthenticationMechanism method. The location should be relative to the current context and start with
+ * "/" e.g. /login.jsp
*/
private static Integer serveLoginPage(final HttpServerExchange exchange, final HttpServletRequest request,
final HttpServletResponse response, final String location) throws ServletException, IOException {