First parts of SAML login module

git-svn-id: https://svn.libreccm.org/ccm/trunk@6167 8810af33-2d31-482b-a856-94f89814c4df
master^2^2^2^2^2^2
jensp 2019-08-24 12:48:14 +00:00 committed by Jens Pelzetter
parent 559bf5f10a
commit 288dd00ca1
3 changed files with 356 additions and 43 deletions

View File

@ -0,0 +1,89 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.arsdigita.kernel.security;
import java.io.IOException;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class SamlLoginModule implements LoginModule {
private CallbackHandler callbackHandler;
private HttpServletRequest request;
private HttpServletResponse response;
private Subject subject;
@Override
public void initialize(final Subject subject,
final CallbackHandler callbackHandler,
final Map<String, ?> sharedState,
final Map<String, ?> options) {
this.callbackHandler = callbackHandler;
this.subject = subject;
}
@Override
public boolean login() throws LoginException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public boolean commit() throws LoginException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public boolean abort() throws LoginException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public boolean logout() throws LoginException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
protected HttpServletRequest getRequest() throws LoginException {
try {
if (request == null) {
final HTTPRequestCallback callback = new HTTPRequestCallback();
callbackHandler.handle(new Callback[]{callback});
request = callback.getRequest();
}
return request;
} catch (IOException | UnsupportedCallbackException ex) {
throw new LoginException("Could not get HTTP request" + ex);
}
}
protected HttpServletResponse getResponse() throws LoginException {
try {
if (response == null) {
final HTTPResponseCallback callback = new HTTPResponseCallback();
callbackHandler.handle(new Callback[]{callback});
response = callback.getResponse();
}
return response;
} catch (IOException | UnsupportedCallbackException ex) {
throw new LoginException("Could not get HTTP response" + ex);
}
}
}

View File

@ -36,8 +36,8 @@ import org.apache.log4j.Logger;
/**
* A record containing server-session scoped security configuration properties.
*
* Accessors of this class may return null. Developers should take care
* to trap null return values in their code.
* Accessors of this class may return null. Developers should take care to trap
* null return values in their code.
*
*
* @author Rafael H. Schloming &lt;rhs@mit.edu&gt;
@ -49,24 +49,30 @@ public class SecurityConfig extends AbstractConfig {
private static final Logger s_log = Logger.getLogger(SecurityConfig.class);
private static SecurityConfig s_config = null;
private static String s_systemAdministratorEmailAddress = null;
/** Size of secret key in bytes. **/
/**
* Size of secret key in bytes. *
*/
public static int SECRET_KEY_BYTES = 16;
/** The class name of the SecurityHelper implementation. Must implement
SecurityHelper interface */
/**
* The class name of the SecurityHelper implementation. Must implement
* SecurityHelper interface
*/
private final Parameter m_securityHelperClass = new SpecificClassParameter(
"waf.security_helper_class", Parameter.REQUIRED,
com.arsdigita.kernel.security.DefaultSecurityHelper.class,
com.arsdigita.kernel.security.SecurityHelper.class);
"waf.security_helper_class", Parameter.REQUIRED,
com.arsdigita.kernel.security.DefaultSecurityHelper.class,
com.arsdigita.kernel.security.SecurityHelper.class);
// /** This parameter is obsolete. */
// private final Parameter m_sessionTrackingMethod = new StringParameter
// ("waf.session_tracking_method", Parameter.REQUIRED, "cookie");
/** List of extensions excluded from authentication cookies.
* Authentication is checked for all requests, but requests with one of
* these extensions will never cause a new cookie to be set.
* Include a leading dot for each extension. */
/**
* List of extensions excluded from authentication cookies. Authentication
* is checked for all requests, but requests with one of these extensions
* will never cause a new cookie to be set. Include a leading dot for each
* extension.
*/
private final Parameter m_excludedExtensions = new StringArrayParameter(
"waf.excluded_extensions", Parameter.REQUIRED,
new String[]{".jpg", ".gif", ".png", ".pdf"});
"waf.excluded_extensions", Parameter.REQUIRED,
new String[]{".jpg", ".gif", ".png", ".pdf"});
// /////////////////////////////////////////////////////////////////////////////
// This section completely moved to com.arsdigita.ui.UIConfig.
// Configuration is not an Initializer task.
@ -107,32 +113,97 @@ public class SecurityConfig extends AbstractConfig {
// ("waf.pagemap.perm_single", Parameter.REQUIRED, "permissions/one");
// ////////////////////////////////////////////////////////////////////////////
private final Parameter m_cookieDurationMinutes = new IntegerParameter(
"waf.pagemap.cookies_duration_minutes", Parameter.OPTIONAL, null);
"waf.pagemap.cookies_duration_minutes", Parameter.OPTIONAL, null);
private final Parameter m_cookieDomain = new StringParameter(
"waf.cookie_domain", Parameter.OPTIONAL, null);
"waf.cookie_domain", Parameter.OPTIONAL, null);
private final Parameter m_loginConfig = new StringArrayParameter(
"waf.login_config", Parameter.REQUIRED,
new String[]{
"Request:com.arsdigita.kernel.security.AdminLoginModule:sufficient",
"Request:com.arsdigita.kernel.security.RecoveryLoginModule:sufficient",
"Request:com.arsdigita.kernel.security.CookieLoginModule:requisite",
"Register:com.arsdigita.kernel.security.LocalLoginModule:requisite",
"Register:com.arsdigita.kernel.security.UserIDLoginModule:requisite",
"Register:com.arsdigita.kernel.security.CookieLoginModule:optional",
"RegisterSSO:com.arsdigita.kernel.security.SimpleSSOLoginModule:requisite",
"RegisterSSO:com.arsdigita.kernel.security.CookieLoginModule:optional"
});
"waf.login_config", Parameter.REQUIRED,
new String[]{
"Request:com.arsdigita.kernel.security.AdminLoginModule:sufficient",
"Request:com.arsdigita.kernel.security.RecoveryLoginModule:sufficient",
"Request:com.arsdigita.kernel.security.CookieLoginModule:requisite",
"Register:com.arsdigita.kernel.security.LocalLoginModule:requisite",
"Register:com.arsdigita.kernel.security.UserIDLoginModule:requisite",
"Register:com.arsdigita.kernel.security.CookieLoginModule:optional",
"RegisterSSO:com.arsdigita.kernel.security.SimpleSSOLoginModule:requisite",
"RegisterSSO:com.arsdigita.kernel.security.CookieLoginModule:optional"
});
private final Parameter m_adminEmail = new StringParameter(
"waf.admin.contact_email", Parameter.OPTIONAL, null);
"waf.admin.contact_email", Parameter.OPTIONAL, null);
private final Parameter m_autoRegistrationOn = new BooleanParameter(
"waf.auto_registration_on", Parameter.REQUIRED, Boolean.TRUE);
private final Parameter m_userBanOn = new BooleanParameter("waf.user_ban_on",
Parameter.REQUIRED,
Boolean.FALSE);
"waf.auto_registration_on", Parameter.REQUIRED, Boolean.TRUE);
private final Parameter m_userBanOn
= new BooleanParameter("waf.user_ban_on",
Parameter.REQUIRED,
Boolean.FALSE);
private final Parameter m_enableQuestion = new BooleanParameter(
"waf.user_question.enable", Parameter.REQUIRED, Boolean.FALSE);
"waf.user_question.enable", Parameter.REQUIRED, Boolean.FALSE);
/**
private final Parameter m_enableSaml = new BooleanParameter(
"waf.enable_saml", Parameter.REQUIRED, Boolean.FALSE);
private final Parameter m_oneLoginSaml2Strict = new BooleanParameter(
"waf.onelogin.saml2.strict", Parameter.REQUIRED, Boolean.TRUE);
private final Parameter m_oneLoginSaml2Debug = new BooleanParameter(
"waf.onelogin.saml2.debug", Parameter.REQUIRED, Boolean.FALSE);
private final Parameter m_oneLoginSaml2SpEntityId = new StringParameter(
"waf.onelogin.saml2.sp.entityid",
Parameter.REQUIRED,
"http://localhost:8080/ccm-saml/metadata");
private final Parameter m_oneLoginSaml2SpAssertationConsumerServiceUrl
= new StringParameter(
"waf.onelogin.saml2.sp.assertion_consumer_service.url",
Parameter.REQUIRED,
"http://localhost:8080/ccm-saml/acs");
private final Parameter m_oneLoginSaml2SpAssertationConsumerServiceBinding
= new StringParameter(
"waf.onelogin.saml2.sp.assertion_consumer_service.binding",
Parameter.REQUIRED,
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST");
private final Parameter m_oneLoginSaml2SpSingleLogoutServiceUrl
= new StringParameter(
"waf.onelogin.saml2.sp.single_logout_service.url",
Parameter.REQUIRED,
"http://localhost:8080/ccm-saml/sls");
private final Parameter m_oneLoginSaml2SpSingleLogoutServiceBinding
= new StringParameter(
"waf.onelogin.saml2.sp.single_logout_service.binding",
Parameter.REQUIRED,
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect");
private final Parameter m_oneLoginSaml2SpNameIdFormat = new StringParameter(
"waf.onelogin.saml2.sp.nameidformat",
Parameter.REQUIRED,
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified");
private final Parameter m_oneLoginSaml2IdpEntityId = new StringParameter(
"waf.onelogin.saml2.idp.entityid",
Parameter.REQUIRED,
"");
private final Parameter m_oneLoginSaml2IdpSingleSignOnServiceUrl
= new StringParameter(
"waf.onelogin.saml2.idp.single_sign_on_service.url",
Parameter.REQUIRED,
"");
private final Parameter m_oneLoginSaml2IdpSingleSignOnServiceBinding
= new StringParameter(
"waf.onelogin.saml2.idp.single_sign_on_service.binding",
Parameter.REQUIRED,
"");
private final Parameter m_oneLoginSaml2IdpSingleLogoutServiceUrl
= new StringParameter(
"waf.onelogin.saml2.idp.single_logout_service.url",
Parameter.REQUIRED,
"");
private final Parameter m_oneLoginSaml2IdpSingleLogoutServiceResponseUrl
= new StringParameter(
"waf.onelogin.saml2.idp.single_logout_service.response.url",
Parameter.REQUIRED,
"");
private final Parameter m_oneLoginSaml2IdpSingleLogoutServiceBinding
= new StringParameter(
"waf.onelogin.saml2.idp.single_logout_service.binding",
Parameter.REQUIRED,
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect");
/**
* Constructs an empty SecurityConfig object
*/
public SecurityConfig() {
@ -149,12 +220,28 @@ public class SecurityConfig extends AbstractConfig {
register(m_userBanOn);
register(m_enableQuestion);
register(m_enableSaml);
register(m_oneLoginSaml2Debug);
register(m_oneLoginSaml2IdpEntityId);
register(m_oneLoginSaml2IdpSingleLogoutServiceBinding);
register(m_oneLoginSaml2IdpSingleLogoutServiceResponseUrl);
register(m_oneLoginSaml2IdpSingleLogoutServiceUrl);
register(m_oneLoginSaml2IdpSingleSignOnServiceBinding);
register(m_oneLoginSaml2IdpSingleSignOnServiceUrl);
register(m_oneLoginSaml2SpAssertationConsumerServiceBinding);
register(m_oneLoginSaml2SpAssertationConsumerServiceUrl);
register(m_oneLoginSaml2SpEntityId);
register(m_oneLoginSaml2SpNameIdFormat);
register(m_oneLoginSaml2SpSingleLogoutServiceBinding);
register(m_oneLoginSaml2SpSingleLogoutServiceUrl);
register(m_oneLoginSaml2Strict);
loadInfo();
}
/**
* Returns the singleton configuration record for the runtime
* environment.
* Returns the singleton configuration record for the runtime environment.
*
* @return The <code>RuntimeConfig</code> record; it cannot be null
*/
@ -168,7 +255,7 @@ public class SecurityConfig extends AbstractConfig {
}
/**
*
*
* @return
*/
public final Class getSecurityHelperClass() {
@ -183,7 +270,7 @@ public class SecurityConfig extends AbstractConfig {
// return (String) get(m_sessionTrackingMethod);
// }
/**
*
*
* @return
*/
public final List getExcludedExtensions() {
@ -213,22 +300,21 @@ public class SecurityConfig extends AbstractConfig {
}
return email;
}
public Boolean getEnableQuestion() {
return (Boolean) get(m_enableQuestion);
}
private static synchronized String getSystemAdministratorEmailAddress() {
if (s_systemAdministratorEmailAddress == null) {
ObjectPermissionCollection perms =
PermissionService.
getGrantedUniversalPermissions();
ObjectPermissionCollection perms = PermissionService.
getGrantedUniversalPermissions();
perms.addEqualsFilter("granteeIsUser", Boolean.TRUE);
perms.clearOrder();
perms.addOrder("granteeID");
if (perms.next()) {
s_systemAdministratorEmailAddress = perms.getGranteeEmail().
toString();
toString();
perms.close();
} else {
// Haven't found anything. We don't want to repeat this query
@ -242,4 +328,67 @@ public class SecurityConfig extends AbstractConfig {
public final boolean isAutoRegistrationOn() {
return ((Boolean) get(m_autoRegistrationOn)).booleanValue();
}
public final boolean getEnableSaml() {
return (Boolean) get(m_enableSaml);
}
public final Boolean getOneLoginSaml2Strict() {
return (Boolean) get(m_oneLoginSaml2Strict);
}
public final Boolean getM_oneLoginSaml2Debug() {
return (boolean) get(m_oneLoginSaml2Debug);
}
public final String getM_oneLoginSaml2SpEntityId() {
return (String) get(m_oneLoginSaml2SpEntityId);
}
public final String getOneLoginSaml2SpAssertationConsumerServiceUrl() {
return (String) get(m_oneLoginSaml2SpAssertationConsumerServiceUrl);
}
public final String getOneLoginSaml2SpAssertationConsumerServiceBinding() {
return (String) get(m_oneLoginSaml2SpAssertationConsumerServiceBinding);
}
public final String getOneLoginSaml2SpSingleLogoutServiceUrl() {
return (String) get(m_oneLoginSaml2SpSingleLogoutServiceUrl);
}
public final String getOneLoginSaml2SpSingleLogoutServiceBinding() {
return (String) get(m_oneLoginSaml2SpSingleLogoutServiceBinding);
}
public final String getOneLoginSaml2SpNameIdFormat() {
return (String) get(m_oneLoginSaml2SpNameIdFormat);
}
public final String getOneLoginSaml2IdpEntityId() {
return (String) get(m_oneLoginSaml2IdpEntityId);
}
public final String getOneLoginSaml2IdpSingleSignOnServiceUrl() {
return (String) get(m_oneLoginSaml2IdpSingleSignOnServiceUrl);
}
public final String getOneLoginSaml2IdpSingleSignOnServiceBinding() {
return (String) get(m_oneLoginSaml2IdpSingleSignOnServiceBinding);
}
public final String getOneLoginSaml2IdpSingleLogoutServiceUrl() {
return (String) get(m_oneLoginSaml2IdpSingleLogoutServiceUrl);
}
public final String getOneLoginSaml2IdpSingleLogoutServiceResponseUrl() {
return (String) get(m_oneLoginSaml2IdpSingleLogoutServiceResponseUrl);
}
public final String getOneLoginSaml2IdpSingleLogoutServiceBinding() {
return (String) get(m_oneLoginSaml2IdpSingleLogoutServiceBinding);
}
}

View File

@ -28,6 +28,81 @@ waf.user_question_enable.purpose=Enable question if a user has forgotten its pas
waf.user_question_enable.example=false
waf.user_question_enable.format=true|false
waf.enable_saml.title=Enable SAML
waf.enable_saml.purpose=Enable authentication via SAML
waf.enable_saml.example=false
waf.enable_saml.format=true|false
waf.onelogin.saml2.strict.title=Strict mode for OneLogin
waf.onelogin.saml2.strict.purpose=
waf.onelogin.saml2.strict.example=true
waf.onelogin.saml2.strict.format=true|false
waf.onelogin.saml2.debug.title=Enable OneLogin debug messages
waf.onelogin.saml2.debug.purpose=Show debug messages for SAML
waf.onelogin.saml2.debug.example=false
waf.onelogin.saml2.debug.format=true|false
waf.onelogin.saml2.sp.entityid.title=URL to informations about this application.
waf.onelogin.saml2.sp.entityid.purpose
waf.onelogin.saml2.sp.entityid.example=http://localhost:8080/ccm-saml/
waf.onelogin.saml2.sp.entityid.format=[string]
waf.onelogin.saml2.sp.assertion_consumer_service.url.title=Consumer service URL
waf.onelogin.saml2.sp.assertion_consumer_service.url.purpose
waf.onelogin.saml2.sp.assertion_consumer_service.url.example=
waf.onelogin.saml2.sp.assertion_consumer_service.url.format=[string]
waf.onelogin.saml2.sp.assertion_consumer_service.binding.title=Service binding
waf.onelogin.saml2.sp.assertion_consumer_service.binding.purpose=
waf.onelogin.saml2.sp.assertion_consumer_service.binding.example=
waf.onelogin.saml2.sp.assertion_consumer_service.binding.format=[string]
waf.onelogin.saml2.sp.single_logout_service.url.title=Logout URL
waf.onelogin.saml2.sp.single_logout_service.url.purpose=
waf.onelogin.saml2.sp.single_logout_service.url.example=
waf.onelogin.saml2.sp.single_logout_service.url.format=[string]
waf.onelogin.saml2.sp.single_logout_service.binding.title=Logout binding
waf.onelogin.saml2.sp.single_logout_service.binding.purpose=
waf.onelogin.saml2.sp.single_logout_service.binding.example=
waf.onelogin.saml2.sp.single_logout_service.binding.format=[string]
waf.onelogin.saml2.sp.nameidformat.title=Name ID format
waf.onelogin.saml2.sp.nameidformat.purpose=
waf.onelogin.saml2.sp.nameidformat.example=
waf.onelogin.saml2.sp.nameidformat.format=[string]
waf.onelogin.saml2.idp.entityid.title=IDP Entity ID
waf.onelogin.saml2.idp.entityid.purpose=
waf.onelogin.saml2.idp.entityid.example=
waf.onelogin.saml2.idp.entityid.format=[string]
waf.onelogin.saml2.idp.single_sign_on_service.url.title=Single Sign On Service URL
waf.onelogin.saml2.idp.single_sign_on_service.url.purpose=
waf.onelogin.saml2.idp.single_sign_on_service.url.example=
waf.onelogin.saml2.idp.single_sign_on_service.url.format=[string]
waf.onelogin.saml2.idp.single_sign_on_service.binding.title=Single Sign On Service URL
waf.onelogin.saml2.idp.single_sign_on_service.binding.purpose=
waf.onelogin.saml2.idp.single_sign_on_service.binding.example=
waf.onelogin.saml2.idp.single_sign_on_service.binding.format=[string]
waf.onelogin.saml2.idp.single_logout_service.url.title=Single Logout Service URL
waf.onelogin.saml2.idp.single_logout_service.url.purpose=
waf.onelogin.saml2.idp.single_logout_service.url.example=
waf.onelogin.saml2.idp.single_logout_service.url.format=[string]
waf.onelogin.saml2.idp.single_logout_service.response.url.title=Single Logout Service Response URL
waf.onelogin.saml2.idp.single_logout_service.response.url.purpose=
waf.onelogin.saml2.idp.single_logout_service.response.url.example=
waf.onelogin.saml2.idp.single_logout_service.response.url.format=[string]
waf.onelogin.saml2.idp.single_logout_service.binding.title=Logout Service Binding
waf.onelogin.saml2.idp.single_logout_service.binding.purpose=
waf.onelogin.saml2.idp.single_logout_service.binding.example=
waf.onelogin.saml2.idp.single_logout_service.binding.format=[string]
# Moved to com.arsdigita.ui.UIConfig (2011-02).
# Retained here for easy reference during transition phase
# waf.pagemap.root.title=Root Page