diff --git a/ccm-core/src/com/arsdigita/kernel/security/SamlLoginModule.java b/ccm-core/src/com/arsdigita/kernel/security/SamlLoginModule.java
new file mode 100644
index 000000000..91d700964
--- /dev/null
+++ b/ccm-core/src/com/arsdigita/kernel/security/SamlLoginModule.java
@@ -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 Jens Pelzetter
+ */
+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 sharedState,
+ final Map 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);
+ }
+ }
+
+}
diff --git a/ccm-core/src/com/arsdigita/kernel/security/SecurityConfig.java b/ccm-core/src/com/arsdigita/kernel/security/SecurityConfig.java
index 3a0c15e3c..35c25e8c1 100755
--- a/ccm-core/src/com/arsdigita/kernel/security/SecurityConfig.java
+++ b/ccm-core/src/com/arsdigita/kernel/security/SecurityConfig.java
@@ -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 <rhs@mit.edu>
@@ -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 RuntimeConfig 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);
+ }
+
+
+
}
diff --git a/ccm-core/src/com/arsdigita/kernel/security/SecurityConfig_parameter.properties b/ccm-core/src/com/arsdigita/kernel/security/SecurityConfig_parameter.properties
index 2976be7d4..91434ea77 100755
--- a/ccm-core/src/com/arsdigita/kernel/security/SecurityConfig_parameter.properties
+++ b/ccm-core/src/com/arsdigita/kernel/security/SecurityConfig_parameter.properties
@@ -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