Skip to content

Commit

Permalink
Merge pull request #24635 from arjantijms/refactor_loginmodules
Browse files Browse the repository at this point in the history
Refactor and clean login modules
  • Loading branch information
arjantijms authored Oct 13, 2023
2 parents c923ebb + ac47012 commit ab6951f
Show file tree
Hide file tree
Showing 14 changed files with 262 additions and 371 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,22 @@

package com.sun.enterprise.security.auth.realm.pam;

import java.util.Collections;
import static java.util.Collections.enumeration;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.SEVERE;

import com.sun.enterprise.security.auth.realm.Realm;
import com.sun.enterprise.security.auth.realm.exceptions.BadRealmException;
import com.sun.enterprise.security.auth.realm.exceptions.NoSuchRealmException;
import com.sun.enterprise.security.auth.realm.exceptions.NoSuchUserException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jvnet.hk2.annotations.Service;
import org.jvnet.libpam.PAM;
import org.jvnet.libpam.PAMException;

import com.sun.appserv.security.AppservRealm;
import com.sun.enterprise.security.auth.realm.exceptions.BadRealmException;
import com.sun.enterprise.security.auth.realm.exceptions.NoSuchRealmException;
import com.sun.enterprise.security.auth.realm.exceptions.NoSuchUserException;
import org.jvnet.libpam.UnixUser;

/**
* Realm wrapper for supporting PAM based authentication for all Unix machines. The PAM realm uses the Operating
Expand All @@ -41,7 +42,7 @@
*/

@Service
public final class PamRealm extends AppservRealm {
public final class PamRealm extends Realm {

// Descriptive string of the authentication type of this realm.
public static final String AUTH_TYPE = "pam";
Expand Down Expand Up @@ -77,13 +78,41 @@ public String getAuthType() {
return AUTH_TYPE;
}

public String[] authenticate(String username, String password) {
UnixUser user = null;
try {
user = new PAM(getPamService()).authenticate(username, password);
} catch (PAMException e) {
_logger.log(SEVERE, "pam_exception_authenticate", e);
}

if (user == null) { // JAAS behavior
return null;
}

_logger.log(FINE, () -> "PAM login succeeded for: " + username);

// Get the groups from the libpam4j UnixUser class that has been returned after a successful authentication.

String[] groups = null;
Set<String> groupSet = user.getGroups();

if (groupSet != null) {
groups = groupSet.toArray(String[]::new);
} else {
// Empty group list, create a zero-length group list
groups = new String[0];
}

return groups;
}

@Override
public Enumeration getGroupNames(String username) throws NoSuchUserException {
public Enumeration<String> getGroupNames(String username) throws NoSuchUserException {
try {
Set<String> groupsSet = new PAM(PAM_SERVICE).getGroupsOfUser(username);
return Collections.enumeration(groupsSet);
return enumeration(new UnixUser(username).getGroups());
} catch (PAMException ex) {
Logger.getLogger(PamRealm.class.getName()).log(Level.SEVERE, "pam_exception_getgroupsofuser", ex);
Logger.getLogger(PamRealm.class.getName()).log(SEVERE, "pam_exception_getgroupsofuser", ex);
return null;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation
* Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation.
* Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand Down Expand Up @@ -50,9 +50,6 @@ public abstract class DigestLoginModule implements LoginModule {
protected static final Logger _logger = LogDomains.getLogger(DigestLoginModule.class, LogDomains.SECURITY_LOGGER);

private Subject subject;
private CallbackHandler handler;
private Map<String, ?> sharedState;
private Map<String, ?> options;
protected boolean _succeeded;
protected boolean _commitSucceeded;
protected UserPrincipal _userPrincipal;
Expand All @@ -65,12 +62,8 @@ public DigestLoginModule() {
@Override
public final void initialize(Subject subject, CallbackHandler handler, Map<String, ?> sharedState, Map<String, ?> options) {
this.subject = subject;
this.handler = handler;
this.sharedState = sharedState;
this.options = options;
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "Login module initialized: " + this.getClass().toString());
}

_logger.log(Level.FINE, () -> "Login module initialized: " + this.getClass().toString());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@

package com.sun.enterprise.security.ee.auth.login;

import static java.util.logging.Level.SEVERE;

import com.sun.enterprise.security.auth.realm.exceptions.InvalidOperationException;
import com.sun.enterprise.security.auth.realm.exceptions.NoSuchUserException;
import java.util.Enumeration;
import java.util.logging.Level;

/**
* @author K.Venugopal@sun.com
Expand All @@ -30,10 +31,11 @@ public class JDBCDigestLoginModule extends DigestLoginModule {
@Override
protected Enumeration<String> getGroups(String username) {
try {
return this.getRealm().getGroupNames(username);
return getRealm().getGroupNames(username);
} catch (InvalidOperationException | NoSuchUserException ex) {
_logger.log(Level.SEVERE, null, ex);
_logger.log(SEVERE, null, ex);
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*
* Copyright (c) 2023 Contributors to the Eclipse Foundation.
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand All @@ -16,51 +17,45 @@

package com.sun.enterprise.security.ee.auth.login;

import java.util.Arrays;
import java.util.logging.Level;
import static com.sun.enterprise.util.Utility.isEmpty;
import static java.util.logging.Level.FINEST;

import com.sun.enterprise.security.auth.login.PasswordLoginModule;
import com.sun.enterprise.security.auth.login.common.LoginException;
import com.sun.enterprise.security.BasePasswordLoginModule;
import com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm;
import java.util.Arrays;
import javax.security.auth.login.LoginException;

/**
* This class implement a JDBC Login module for Glassfish. The work is derivated from Sun's sample JDBC login module.
* Enhancement has been done to use latest features. sample setting in server.xml for JDBCLoginModule
*
* @author Jean-Baptiste Bugeaud
*/
public class JDBCLoginModule extends PasswordLoginModule {
public class JDBCLoginModule extends BasePasswordLoginModule {
/**
* Perform JDBC authentication. Delegates to JDBCRealm.
* @throws javax.security.auth.login.LoginException
*
* @throws LoginException If login fails (JAAS login() behavior).
* @throws javax.security.auth.login.LoginException
*/
@Override
protected void authenticate() throws LoginException {
if (!(_currentRealm instanceof JDBCRealm)) {
String msg = sm.getString("jdbclm.badrealm");
throw new LoginException(msg);
}

final JDBCRealm jdbcRealm = (JDBCRealm) _currentRealm;
protected void authenticateUser() throws LoginException {
final JDBCRealm jdbcRealm = getRealm(JDBCRealm.class, "jdbclm.badrealm");

// A JDBC user must have a name not null and non-empty.
if (_username == null || _username.length() == 0) {
String msg = sm.getString("jdbclm.nulluser");
throw new LoginException(msg);
if (isEmpty(_username)) {
throw new LoginException(sm.getString("jdbclm.nulluser"));
}

String[] grpList = jdbcRealm.authenticate(_username, getPasswordChar());
String[] groups = jdbcRealm.authenticate(_username, getPasswordChar());

if (grpList == null) { // JAAS behavior
String msg = sm.getString("jdbclm.loginfail", _username);
throw new LoginException(msg);
if (groups == null) { // JAAS behavior
throw new LoginException(sm.getString("jdbclm.loginfail", _username));
}

if (_logger.isLoggable(Level.FINEST)) {
_logger.finest("JDBC login succeeded for: " + _username + " groups:" + Arrays.toString(grpList));
}
_logger.log(FINEST, () -> "JDBC login succeeded for: " + _username + " groups:" + Arrays.toString(groups));

commitAuthentication(_username, getPasswordChar(), _currentRealm, grpList);
commitUserAuthentication(groups);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*
* Copyright (c) 2023 Contributors to the Eclipse Foundation.
* Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand All @@ -16,82 +17,39 @@

package com.sun.enterprise.security.ee.auth.login;

import java.util.Set;
import java.util.logging.Level;
import static com.sun.enterprise.util.Utility.isEmpty;
import static java.util.logging.Level.FINE;

import javax.security.auth.login.LoginException;

import org.jvnet.libpam.PAM;
import org.jvnet.libpam.PAMException;
import org.jvnet.libpam.UnixUser;

import com.sun.appserv.security.AppservPasswordLoginModule;
import com.sun.enterprise.security.BasePasswordLoginModule;
import com.sun.enterprise.security.auth.realm.pam.PamRealm;
import javax.security.auth.login.LoginException;

/**
* This is the main LoginModule for PAM realm that invokes the calls to libpam4j classes to authenticate the given
* username and password
*
* @author Nithya Subramanian
*/
public class PamLoginModule extends AppservPasswordLoginModule {
public class PamLoginModule extends BasePasswordLoginModule {

@Override
protected void authenticateUser() throws LoginException {
PamRealm pamRealm = getRealm(PamRealm.class, "pamrealm.invalid_realm");

// A Unix user must have a name not null so check here.
if (_username == null || _username.length() == 0) {
if (isEmpty(_username)) {
throw new LoginException("Invalid Username");
}
UnixUser user = authenticate(_username, _password);

if (user == null) { // JAAS behavior
String[] groups = pamRealm.authenticate(_username, _password);

if (groups == null) { // JAAS behavior
throw new LoginException("Failed Pam Login for " + _username);
}
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "PAM login succeeded for: " + _username);
}

/*
* Get the groups from the libpam4j UnixUser class that has been returned after a successful authentication.
*/

String[] grpList = null;
Set<String> groupSet = user.getGroups();
_logger.log(FINE, () -> "PAM login succeeded for: " + _username);

if (groupSet != null) {
grpList = new String[groupSet.size()];
user.getGroups().toArray(grpList);
} else {
// Empty group list, create a zero-length group list
grpList = new String[0];
}
commitUserAuthentication(grpList);
commitUserAuthentication(groups);
}

/**
* Invokes the authentication call.This class uses the default PAM service - sshd
*
* @param username OS User to authenticate.
* @param password Given password.
* @returns null if authentication failed, returns the UnixUser object if authentication succeeded.
*
*/
private UnixUser authenticate(String username, String password) throws LoginException {
UnixUser user = null;
String pamService = null;

if (!(_currentRealm instanceof PamRealm)) {
throw new LoginException("pamrealm.invalid_realm");
}
pamService = ((PamRealm) _currentRealm).getPamService();

try {
user = new PAM(pamService).authenticate(username, password);

} catch (PAMException e) {
_logger.log(Level.SEVERE, "pam_exception_authenticate", e);
}
return user;
}
}
Loading

0 comments on commit ab6951f

Please sign in to comment.