CCM NG: Added the SecurityConfig class to CCM NG

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@3524 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2015-07-18 15:46:31 +00:00
parent e01c82e6c5
commit a046640210
10 changed files with 611 additions and 1 deletions

View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.kernel.security;
import javax.servlet.http.HttpServletRequest;
/**
* Default implementation of SecurityHelper interface.
*
* @author Sameer Ajmani
* @see SecurityHelper
*/
public class DefaultSecurityHelper implements SecurityHelper {
/**
* Determines whether the request is secure by calling
* <code>req.isSecure()</code>.
*
* @param request The current {@link HttpServletRequest}
*
* @return req.isSecure().
*
*/
@Override
public boolean isSecure(final HttpServletRequest request) {
return request.isSecure();
}
/**
* Determines whether the current request requires that the user be logged
* in.
*
* @param request The current {@link HttpServletRequest}
*
* @return <code>true</code> if the request is secure and the page is not on
* a list of allowed pages (such as the login page and the
* bad-password page), <code>false</code> otherwise.
*
*/
@Override
public boolean requiresLogin(final HttpServletRequest request) {
// XXX workaround, old is broken anyway,
// it doesn't take into account dispatcher prefix ( /ccm )
return false;
}
/**
* Returns the full URL of the login page stored in the page map.
*
* @param request The current {@link HttpServletRequest}
*
* @return the full URL of the login page.
*
*/
@Override
public String getLoginURL(final HttpServletRequest request) {
//ToDo: Add correct method call here.
//return UI.getLoginPageURL();
return "";
}
}

View File

@ -0,0 +1,239 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.kernel.security;
import com.arsdigita.runtime.AbstractConfig;
import com.arsdigita.util.parameter.BooleanParameter;
import com.arsdigita.util.parameter.IntegerParameter;
import com.arsdigita.util.parameter.Parameter;
import com.arsdigita.util.parameter.SpecificClassParameter;
import com.arsdigita.util.parameter.StringArrayParameter;
import com.arsdigita.util.parameter.StringParameter;
import java.util.Arrays;
import java.util.List;
/**
* 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.
*
*
* @author Rafael H. Schloming &lt;rhs@mit.edu&gt;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class SecurityConfig extends AbstractConfig {
private static SecurityConfig s_config = null;
private static String s_systemAdministratorEmailAddress = null;
/**
* Size of secret key in bytes. *
*/
@SuppressWarnings("PublicField")
public static int SECRET_KEY_BYTES = 16;
/**
* 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);
/**
* 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"});
private final Parameter m_cookieDurationMinutes = new IntegerParameter(
"waf.pagemap.cookies_duration_minutes", Parameter.OPTIONAL, null);
private final Parameter m_cookieDomain = new StringParameter(
"waf.cookie_domain", Parameter.OPTIONAL, null);
private final Parameter m_loginConfig = new StringArrayParameter(
"waf.login_config", Parameter.REQUIRED,
new String[]{
"Register:com.arsdigita.kernel.security.LocalLoginModule:requisite",});
private final Parameter m_adminEmail = new StringParameter(
"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);
private final Parameter m_enableQuestion = new BooleanParameter(
"waf.user_question.enable", Parameter.REQUIRED, Boolean.FALSE);
/**
* The default hash algorithm used for new passwords. Default is SHA-512
* which should sufficient for good security.
*/
private final Parameter m_hashAlgorithm = new StringParameter(
"waf.security.hash_algorithm", Parameter.REQUIRED, "SHA-512");
/**
* Default length of the salt for new passwords.
*/
private final Parameter m_saltLength = new IntegerParameter(
"waf.security.salt_length", Parameter.REQUIRED, 256);
/**
* Constructs an empty SecurityConfig object
*/
public SecurityConfig() {
register(m_securityHelperClass);
register(m_excludedExtensions);
register(m_cookieDomain);
register(m_loginConfig);
register(m_cookieDurationMinutes);
register(m_adminEmail);
register(m_autoRegistrationOn);
register(m_userBanOn);
register(m_enableQuestion);
register(m_hashAlgorithm);
register(m_saltLength);
loadInfo();
}
/**
* Returns the singleton configuration record for the runtime environment.
*
* @return The <code>RuntimeConfig</code> record; it cannot be null
*/
public static final synchronized SecurityConfig getConfig() {
if (s_config == null) {
s_config = new SecurityConfig();
s_config.load();
}
return s_config;
}
/**
*
* @return
*/
public final Class getSecurityHelperClass() {
return (Class) get(m_securityHelperClass);
}
// /**
// * Obsolete!
// * @return
// */
// public final String getSessionTrackingMethod() {
// return (String) get(m_sessionTrackingMethod);
// }
/**
*
* @return
*/
public final List<String> getExcludedExtensions() {
return Arrays.asList((String[]) get(m_excludedExtensions));
}
public String getCookieDomain() {
return (String) get(m_cookieDomain);
}
String[] getLoginConfig() {
return (String[]) get(m_loginConfig);
}
Integer getCookieDurationMinutes() {
return (Integer) get(m_cookieDurationMinutes);
}
boolean isUserBanOn() {
return ((Boolean) get(m_userBanOn)).booleanValue();
}
public String getAdminContactEmail() {
String email = (String) get(m_adminEmail);
// Return empty string instead of looking up into the database. If no
// email if configured for the admin we consider that as a configuration
// issue.
if (email == null || email.isEmpty()) {
return "";
} else {
return email;
}
// if (email == null || email.trim().length() == 0) {
// email = getSystemAdministratorEmailAddress();
// }
// return email;
}
public Boolean getEnableQuestion() {
return (Boolean) get(m_enableQuestion);
}
// private static synchronized String getSystemAdministratorEmailAddress() {
// if (s_systemAdministratorEmailAddress == null) {
// ObjectPermissionCollection perms = PermissionService.
// getGrantedUniversalPermissions();
// perms.addEqualsFilter("granteeIsUser", Boolean.TRUE);
// perms.clearOrder();
// perms.addOrder("granteeID");
// if (perms.next()) {
// s_systemAdministratorEmailAddress = perms.getGranteeEmail().
// toString();
// perms.close();
// } else {
// // Haven't found anything. We don't want to repeat this query
// // over and over again.
// s_systemAdministratorEmailAddress = "";
// }
// }
// return s_systemAdministratorEmailAddress;
// }
public final boolean isAutoRegistrationOn() {
return ((Boolean) get(m_autoRegistrationOn)).booleanValue();
}
public String getHashAlgorithm() {
return (String) get(m_hashAlgorithm);
}
public Integer getSaltLength() {
return (Integer) get(m_saltLength);
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.kernel.security;
import javax.servlet.http.HttpServletRequest;
/**
* Provides methods for determining security properties for a request.
*
* @author Sameer Ajmani
* @version $Id: SecurityHelper.java 287 2005-02-22 00:29:02Z sskracic $
*/
public interface SecurityHelper {
/**
* Determines whether the given request is secure. Implementation may
* simply return <code>req.isSecure()</code>, but certain deployments
* may use other information (such as the requested port number)
* instead.
*
* @param req the request to check
*
* @return <code>true</code> if the given request uses a secure
* protocol, <code>false</code> otherwise.
**/
public boolean isSecure(HttpServletRequest req);
/**
* Determines whether the given request requires the user to be logged
* in. If this method returns <code>true</code>, the system will call
* <code>getLoginURL</code> to determine where to redirect the client to
* log in.
*
* @param req the request to check
*
* @return <code>true</code> if the given request requires the user to
* be logged in, <code>false</code> otherwise.
**/
public boolean requiresLogin(HttpServletRequest req);
/**
* Determines where to redirect the client to log in. The system calls
* this method if the user fails to log in and
* <code>requiresLogin(req)</code> is true.
*
* @return the URL to which the client should be redirected to log in,
* never null.
**/
public String getLoginURL(HttpServletRequest req);
}

View File

@ -0,0 +1,39 @@
waf.login_config.title=Login Configuration
waf.login_config.purpose=Enter JAAS login configuration, using the syntax described in Javadoc for com.arsdigita.kernel.security.LoginConfig
waf.login_config.example=Request:com.arsdigita.kernel.security.AdminLoginModule:sufficient,Register:com.arsdigita.kernel.security.LocalLoginModule:requisite
waf.login_config.format=[string,string,...]
waf.cookie_domain.title=Cookie Domain
waf.cookie_domain.purpose=Enter the domain to which the Aplaws authentication cookie is presented
waf.cookie_domain.example=.example.com
waf.cookie_domain.format=[string]
waf.admin.contact_email.title=System administrator email address
waf.admin.contact_email.purpose=Email address that will be displayed on footer of login/admin pages, if empty then site-wide admin email will be substituted
waf.admin.contact_email.example=ccmadmin@example.com
waf.admin.contact_email.format=[string]
waf.auto_registration_on.title=Auto Registration
waf.auto_registration_on.purpose=New users get automatically redirected to the create new user form
waf.auto_registration_on.example=true
waf.auto_registration_on.format=true|false
waf.user_ban_on.title=User Ban
waf.user_ban_on.purpose=Check on each access if user has been banned from the site.
waf.user_ban_on.example=false
waf.user_ban_on.format=true|false
waf.user_question_enable.title=Enable question
waf.user_question_enable.purpose=Enable question if a user has forgotten its password
waf.user_question_enable.example=false
waf.user_question_enable.format=true|false
waf.security.hash_algorithm.title=Default Hash Algorithm
waf.security.hash_algorithm.purpose=Sets the Hash Algorithm to use for new passwords. The available algorithms depend on the Java Runtime.
waf.security.hash_algorithm.example=SHA-512
waf.security.hash_algorithm.format=[string]
waf.security.salt_length.title=Default Salt Length
waf.security.salt_length.purpose=Sets the length of the salt for new passwords
waf.security.salt_length.example=256
waf.security.salt_length.format=[int]

View File

@ -37,7 +37,6 @@ import org.junit.Test;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.libreccm.tests.categories.IntegrationTest; import org.libreccm.tests.categories.IntegrationTest;
import sun.util.locale.StringTokenIterator;
import java.util.StringTokenizer; import java.util.StringTokenizer;

View File

@ -0,0 +1,163 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.kernel.security;
import static org.hamcrest.Matchers.*;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.jboss.shrinkwrap.resolver.api.maven.Maven;
import org.jboss.shrinkwrap.resolver.api.maven.PomEquippedResolveStage;
import org.junit.After;
import org.junit.AfterClass;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.libreccm.tests.categories.IntegrationTest;
import java.io.File;
import java.util.List;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RunWith(Arquillian.class)
@Category(IntegrationTest.class)
public class SecurityConfigTest {
public SecurityConfigTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
@Deployment
public static WebArchive createDeployment() {
final PomEquippedResolveStage pom = Maven
.resolver()
.loadPomFromFile("pom.xml");
final PomEquippedResolveStage dependencies = pom
.importCompileAndRuntimeDependencies();
final File[] libs = dependencies.resolve().withTransitivity().asFile();
for (File lib : libs) {
System.err.printf("Adding file '%s' to test archive...%n",
lib.getName());
}
return ShrinkWrap
.create(WebArchive.class,
"LibreCCM-com.arsdigita.kernel.security.SecurityConfigTest.war")
//.addPackage(CcmObject.class.getPackage())
.addPackage(com.arsdigita.kernel.KernelConfig.class.getPackage())
.addPackage(com.arsdigita.kernel.security.SecurityConfig.class
.getPackage())
.addPackage(com.arsdigita.runtime.AbstractConfig.class.getPackage())
.addPackage(com.arsdigita.util.parameter.AbstractParameter.class.
getPackage())
.addPackage(com.arsdigita.util.JavaPropertyReader.class.
getPackage())
.addPackage(com.arsdigita.web.CCMApplicationContextListener.class
.getPackage())
.addPackage(com.arsdigita.xml.XML.class.getPackage())
.addPackage(com.arsdigita.xml.formatters.DateFormatter.class
.getPackage())
.addPackage(org.libreccm.tests.categories.IntegrationTest.class
.getPackage())
.addAsLibraries(libs)
.addAsResource(
"configtests/com/arsdigita/kernel/security/SecurityConfigTest/ccm-core.config",
"ccm-core.config")
.addAsWebInfResource(
"configtests/com/arsdigita/kernel/security/SecurityConfigTest/registry.properties",
"conf/registry/registry.properties")
.addAsWebInfResource(
"configtests/com/arsdigita/kernel/security/SecurityConfigTest/kernel.properties",
"conf/registry/ccm-core/kernel.properties")
.addAsWebInfResource(
"configtests/com/arsdigita/kernel/security/SecurityConfigTest/security.properties",
"conf/registry/ccm-core/security.properties")
.addAsResource(
"com/arsdigita/kernel/KernelConfig_parameter.properties",
"com/arsdigita/kernel/KernelConfig_parameter.properties")
.addAsResource(
"com/arsdigita/kernel/security/SecurityConfig_parameter.properties",
"com/arsdigita/kernel/security/SecurityConfig_parameter.properties")
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
@Test
public void verifySecurityConfig() {
final SecurityConfig securityConfig = SecurityConfig.getConfig();
final String[] loginConfig = securityConfig.getLoginConfig();
assertThat(loginConfig.length, is(1));
assertThat(loginConfig[0], is(equalTo(
"Register:com.arsdigita.kernel.security.LocalLoginModule:requisite")));
final List<String> excludedExtensions = securityConfig.getExcludedExtensions();
assertThat(excludedExtensions.size(), is(4));
assertThat(excludedExtensions.get(0), is(equalTo(".jpg")));
assertThat(excludedExtensions.get(1), is(equalTo(".gif")));
assertThat(excludedExtensions.get(2), is(equalTo(".png")));
assertThat(excludedExtensions.get(3), is(equalTo(".pdf")));
assertThat(securityConfig.getCookieDurationMinutes(), is(nullValue()));
assertThat(securityConfig.getCookieDomain(),
is(equalTo(".example.org")));
assertThat(securityConfig.getAdminContactEmail(),
is(equalTo("admin@example.org")));
assertThat(securityConfig.isAutoRegistrationOn(), is(false));
assertThat(securityConfig.isUserBanOn(), is(true));
assertThat(securityConfig.getEnableQuestion(), is(false));
assertThat(securityConfig.getHashAlgorithm(), is(equalTo("SHA-256")));
assertThat(securityConfig.getSaltLength(), is(128));
}
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<registry>
<config class="com.arsdigita.kernel.KernelConfig"
storage="ccm-core/kernel.properties"/>
<config class="com.arsdigita.kernel.security.SecurityConfig"
storage="ccm-core/security.properties"/>
</registry>

View File

@ -0,0 +1,15 @@
waf.login_config=Register:com.arsdigita.kernel.security.LocalLoginModule:requisite
waf.cookie_domain=.example.org
waf.admin.contact_email=admin@example.org
waf.auto_registration_on=false
waf.user_ban_on=true
waf.user_question_enable=false
waf.security.hash_algorithm=SHA-256
waf.security.salt_length=128