From: maxcooper Date: Thu, 8 Aug 2002 13:20:46 +0000 (+0000) Subject: Initial revision X-Git-Tag: SF_1_0_B4~1 X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=75bafc0153ccafef252412ddb8c0c8fd68813788;p=securityfilter.git Initial revision --- 75bafc0153ccafef252412ddb8c0c8fd68813788 diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..7d78eef --- /dev/null +++ b/.cvsignore @@ -0,0 +1,4 @@ +build.properties +dist +target +release diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..954f708 --- /dev/null +++ b/LICENSE @@ -0,0 +1,65 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/LICENSE,v 1.1 2002/08/08 13:20:46 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/08/08 13:20:46 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2001 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Struts", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + + + + + diff --git a/README b/README new file mode 100644 index 0000000..1e3da13 --- /dev/null +++ b/README @@ -0,0 +1,80 @@ +$Header: /cvsroot/securityfilter/securityfilter/README,v 1.1 2002/08/08 13:20:46 maxcooper Exp $ +$Revision: 1.1 $ +$Date: 2002/08/08 13:20:46 $ + + + Security Filter v1.0-b4 +====================================== +http://www.securityfilter.org/ +http://securityfilter.sourceforge.com/ + + +What is SecurityFilter? +----------------------- +SecurityFilter is a filter that mimics container-based security. It looks just +like container-based security to your app, as you can call +request.getRemoteUser(), request.isUserInRole(), and request.getUserPrincipal() +and get valid responses. However, it can be deployed within your web app, so you +do not need to set the realm in the server configuration, or put any classes in +the server classpath. The realm interface for SecurityFilter is proprietary, but +it is very simple (2 methods) and should be easy to implement for your project. +The other main advantage is that you can submit the login form without being +forced there by the security mechanism. + +Securityfilter is free software, available under the Apache Software License +v1.1. + + +What's in this package? +----------------------- +Two example apps demonstrate securityfilter in action: + +1. securityfilter-example.war - Basic securityfilter app using native +securityfilter realm implementation. + +2. securityfilter-catalina-example.war - Same as securityfilter-example app with +Tomcat (Catalina) realm implementation and realm adapter class. + +A securityfilter-blank.war example app is also provided as a skeleton to use to +start a new securityfilter application. + + +How to use SecurityFilter +------------------------- +To use the SecurityFilter, you need to do these things: + +- Have jakarta-regexp in your classpath (tested with v1.2) +- Declare the SecurityFilter in your web.xml file, and map everything to it +- Declare your security preferences in WEB-INF/securityfilter-config.xml +- Provide an implementation of SecurityRealmInterface (or extend +SecurityRealmBase) for your app (and give its classname in securityfilter- +config.xml) + +The example apps include web.xml and securityfilter-config.xml file examples. + + +Future Direction +---------------- +This is the first release. It is ready for use and should support everything +needed for most apps. + + +Contributors +------------ +1. Max Cooper maintains the project and wrote much of the code. +2. Torgeir Veimo contributed the Digester-based security-config.xml reader and +did some additional work on supporting the structures in the file (like multiple +roles per constraint). +3. Prakash Malani provided review and Ant help. + + +Feedback +-------- +Let me know what your priorities are, and if there is anything else you would +like to see. Contact me via email (max@maxcooper.com) or use SourceForge to +report bugs or make feature requests (http://securityfilter.sourceforge.com/). + + +Thank you, +Max Cooper + diff --git a/build-webapp.xml b/build-webapp.xml new file mode 100644 index 0000000..2ddb103 --- /dev/null +++ b/build-webapp.xml @@ -0,0 +1,318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build-webapps.xml b/build-webapps.xml new file mode 100644 index 0000000..107e06e --- /dev/null +++ b/build-webapps.xml @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build.properties.sample b/build.properties.sample new file mode 100644 index 0000000..068fe98 --- /dev/null +++ b/build.properties.sample @@ -0,0 +1,39 @@ +# ----------------------------------------------------------------------------- +# build.properties.sample +# +# This is an example "build.properties" file, used to customize building +# Security Filter for your local environment. Make any changes you need, and +# rename this file to "build.properties" in the same directory that contains +# the Security Filter "build.xml" file. +# +# $Id: build.properties.sample,v 1.1 2002/08/08 13:20:46 maxcooper Exp $ +# ----------------------------------------------------------------------------- + +# The catalina JAR file from version 4.0 (or later) of the Jakarta Tomcat +# package. +catalina.jar=/usr/local/jakarta-tomcat-4.0/server/lib/catalina.jar + +# The JAR file containing version 1.0 (or later) of the Beanutils package +# from the Jakarta Commons project. +commons-beanutils.jar=/usr/local/commons-beanutils-1.0/commons-beanutils.jar + +# The JAR file containing version 1.0 (or later) of the Collections package +# from the Jakarta Commons project. +commons-collections.jar=/usr/local/commons-collections-1.0/commons-collections.jar + +# The JAR file containing version 1.0 (or later) of the Digester package +# from the Jakarta Commons project. +commons-digester.jar=/usr/local/commons-digester-1.0/commons-digester.jar + +# The JAR file containing version 1.0 (or later) of the Logging package +# from the Jakarta Commons project. +commons-logging.jar=/usr/local/commons-logging-1.0/commons-logging.jar + +# The JAR file containing version 1.2 (or later) of +# the the Jakarta Regexp project. +jakarta-regexp.jar=/usr/local/jakarta-regexp-1.2/jakarta-regexp-1.2.jar + +# The JAR file containing the Servlet API version 2.3 (or later) classes to +# compile against +servlet.jar=/usr/local/jakarta-servletapi-4/lib/servlet.jar + diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..a62319f --- /dev/null +++ b/build.xml @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/share/MANIFEST.MF b/conf/share/MANIFEST.MF new file mode 100644 index 0000000..742a7f2 --- /dev/null +++ b/conf/share/MANIFEST.MF @@ -0,0 +1,11 @@ +Manifest-Version: 1.0 +Extension-Name: Security Filter +Specification-Title: Security Filter +Specification-Vendor: SecurityFilter.org +Specification-Version: 1.0 +Implementation-Title: Security Filter +Implementation-Vendor: SecurityFilter.org +Implementation-Vendor-Id: org.securityfilter +Implementation-Version: 1.0 +Class-Path: catalina.jar commons-beanutils.jar commons-collections.jar commons-digester.jar commons-logging.jar jakarta-regexp.jar + diff --git a/conf/share/securityfilter-config_1_0.dtd b/conf/share/securityfilter-config_1_0.dtd new file mode 100644 index 0000000..4253d15 --- /dev/null +++ b/conf/share/securityfilter-config_1_0.dtd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/share/securityfilter-config_1_0.xsd b/conf/share/securityfilter-config_1_0.xsd new file mode 100644 index 0000000..eab6b39 --- /dev/null +++ b/conf/share/securityfilter-config_1_0.xsd @@ -0,0 +1,99 @@ + + + + + + Root element for securityfilter config + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/share/web-app_2_3.dtd b/conf/share/web-app_2_3.dtd new file mode 100644 index 0000000..b110d76 --- /dev/null +++ b/conf/share/web-app_2_3.dtd @@ -0,0 +1,1059 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/catalina-example/org/securityfilter/catalina/TrivialCatalinaRealm.java b/src/catalina-example/org/securityfilter/catalina/TrivialCatalinaRealm.java new file mode 100644 index 0000000..ec55b06 --- /dev/null +++ b/src/catalina-example/org/securityfilter/catalina/TrivialCatalinaRealm.java @@ -0,0 +1,123 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/catalina-example/org/securityfilter/catalina/Attic/TrivialCatalinaRealm.java,v 1.1 2002/08/08 13:20:47 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/08/08 13:20:47 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.securityfilter.catalina; + +import org.apache.catalina.realm.GenericPrincipal; +import org.apache.catalina.realm.RealmBase; + +import java.security.Principal; +import java.util.ArrayList; + +/** + * TrivialCatalinaRealm - Trivial Catalina Realm implementation to demonstrate + * org.securityfilter.realm.adapter.CatalinaRealmAdapter adapter class. + * + * @author Max Cooper (max@maxcooper.com) + */ +public class TrivialCatalinaRealm extends RealmBase { + private static final String THE_USERNAME = "username"; + private static final String THE_PASSWORD = "password"; + private static final String THE_ROLE = "inthisrole"; + + /** + * Return a short name for this Realm implementation. + */ + protected String getName() { + return null; + } + + /** + * Return the password associated with the given principal's user name. + */ + protected String getPassword(String s) { + return (THE_USERNAME.equals(s) ? THE_PASSWORD : null); + } + + /** + * Return the Principal associated with the given user name. + */ + protected Principal getPrincipal(String s) { + if (THE_USERNAME.equals(s)) { + ArrayList roleList = new ArrayList(); + roleList.add(THE_ROLE); + return new GenericPrincipal(this, THE_USERNAME, THE_PASSWORD, roleList); + } else { + return null; + } + } + + /** + * Setter for exampleProperty to deomonstrate setting realm properties from config file. + * + * This has no effect other than printing a message when the property is set. + * + * @param value example property value + */ + public void setExampleProperty(String value) { + System.out.println(this.getClass().getName() + ": exampleProperty set to \'" + value + "\'"); + } +} + +// ---------------------------------------------------------------------------- +// EOF \ No newline at end of file diff --git a/src/example/org/securityfilter/example/TrivialSecurityRealm.java b/src/example/org/securityfilter/example/TrivialSecurityRealm.java new file mode 100644 index 0000000..3bf7bc9 --- /dev/null +++ b/src/example/org/securityfilter/example/TrivialSecurityRealm.java @@ -0,0 +1,122 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/example/org/securityfilter/example/Attic/TrivialSecurityRealm.java,v 1.1 2002/08/08 13:20:47 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/08/08 13:20:47 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.securityfilter.example; + +import org.securityfilter.realm.SecurityRealmBase; + +/** + * Trivial implementation of the SecurityRealmInterface. + * + * There is one user: username is 'username', password is 'password' + * And this user is in one role: 'inthisrole' + * + * @author Max Cooper (max@maxcooper.com) + * @version $Revision: 1.1 $ $Date: 2002/08/08 13:20:47 $ + */ +public class TrivialSecurityRealm extends SecurityRealmBase { + private static final String THE_USERNAME = "username"; + private static final String THE_PASSWORD = "password"; + private static final String THE_ROLE = "inthisrole"; + + /** + * Authenticate a user. + * + * Implement this method in a subclass to avoid dealing with Principal objects. + * + * @param username a username + * @param password a plain text password, as entered by the user + * + * @return null if the user cannot be authenticated, otherwise a Pricipal object is returned + */ + public boolean booleanAuthenticate(String username, String password) { + return THE_USERNAME.equals(username) && THE_PASSWORD.equals(password); + } + + /** + * Test for role membership. + * + * Implement this method in a subclass to avoid dealing with Principal objects. + * + * @param principal Principal object representing a user + * @param rolename name of a role to test for membership + * @return true if the user is in the role, false otherwise + */ + public boolean isUserInRole(String username, String role) { + return THE_USERNAME.equals(username) && THE_ROLE.equals(role); + } + + /** + * Setter for exampleProperty to deomonstrate setting realm properties from config file. + * + * This has no effect other than printing a message when the property is set. + * + * @param value example property value + */ + public void setExampleProperty(String value) { + System.out.println(this.getClass().getName() + ": exampleProperty set to \'" + value + "\'"); + } +} + +// ---------------------------------------------------------------------------- +// EOF \ No newline at end of file diff --git a/src/share/org/securityfilter/config/SecurityConfig.java b/src/share/org/securityfilter/config/SecurityConfig.java new file mode 100644 index 0000000..2c3a94e --- /dev/null +++ b/src/share/org/securityfilter/config/SecurityConfig.java @@ -0,0 +1,277 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/config/SecurityConfig.java,v 1.1 2002/08/08 13:20:47 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/08/08 13:20:47 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.securityfilter.config; + +import org.apache.commons.digester.Digester; +import org.securityfilter.realm.SecurityRealmInterface; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +/** + * SecurityConfig gathers information from the security-config.xml file to be used by the filter. + * + * @author Torgeir Veimo (torgeir@pobox.com) + * @author Max Cooper (max@maxcooper.com) + * @version $Revision: 1.1 $ $Date: 2002/08/08 13:20:47 $ + */ +public class SecurityConfig { + + private String loginPage = null; + private String errorPage = null; + private String defaultPage = null; + private ArrayList securityConstraints = null; + private SecurityRealmInterface realm = null; + private Object lastRealm = null; + private boolean validating; + + /** + * Constructor that takes the validating flag and debug level to be used while parsing. + * + * @param validating validate the input file, true = validate, false = don't validate + * @param debugLevel set the debug level to use while parsing + */ + public SecurityConfig(boolean validating) { + this.validating = validating; + } + + /** + * Return the login page url. + */ + public String getLoginPage() { + return loginPage; + } + + /** + * Set the login page URL. This is the page the user will be sent to to login (i.e. the login form). + * + * @param loginPage The login page url (relative to site root) + */ + public void setLoginPage(String loginPage) { + this.loginPage = loginPage; + } + + /** + * Return the error page URL. + */ + public String getErrorPage() { + return errorPage; + } + + /** + * Set the error page URL. This is the page the user will be sent to if login request fails. + * + * @param errorPage The login page URL (relative to site root) + */ + public void setErrorPage(String errorPage) { + this.errorPage = errorPage; + } + + /** + * Return the default page URL. + */ + public String getDefaultPage() { + return defaultPage; + } + + /** + * Set the default page URL. This is the page the user will be sent to if they submit a login request without + * being forced to the login page by the filter. + * + * @param defaultPage The default page URL (relative to site root) + */ + public void setDefaultPage(String defaultPage) { + this.defaultPage = defaultPage; + } + + /** + * Return the realm to use for authentication. This is the outer-most realm if nested realms are used. + * The outer-most realm must be listed first in the configuration file. + */ + public SecurityRealmInterface getRealm() { + return realm; + } + + /** + * Adds a realm to use for authentication. + * + * The first time this method is called, the realm must implement SecurityRealmInterface. + * Subsequent calls can be any kind of object, and setRealm(realm) will be called on the + * last realm passed to this method. This allows nesting of realms for caching or when a + * realm adapter is used. + * + * @param realm The realm to use, or nest in deeper realm + */ + public synchronized void addRealm( + Object realm + ) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + if (this.realm == null) { + this.realm = (SecurityRealmInterface) realm; + lastRealm = realm; + } else { + // call lastRealm.setRealm(realm) + Method addMethod = lastRealm.getClass().getMethod("setRealm", new Class[] { Object.class }); + addMethod.invoke(lastRealm, new Object[] { realm }); + lastRealm = realm; + } + } + + /** + * Return the configured SecurityConstraints. + */ + public List getSecurityConstraints() { + return this.securityConstraints; + } + + /** + * Adds a SecurityConstraint. + * + * @param constraint The SecurityConstraint to add + */ + public void addSecurityConstraint(SecurityConstraint constraint) { + securityConstraints.add(constraint); + } + + /** + * Loads configuration from the specifued configURL. + * + * @param configURL The url to load. + * + * @exception IOException if an input/output error occurs + * @exception SAXException if the file has invalid xml syntax + */ + public void loadConfig(URL configURL) throws IOException, SAXException { + + securityConstraints = new ArrayList(); + + Digester digester = new Digester(); + + digester.push(this); + digester.setValidating(validating); + + // realms + digester.addObjectCreate("securityfilter-config/realm", null, "className"); + digester.addSetProperty("securityfilter-config/realm/realm-param", "name", "value"); + digester.addSetNext("securityfilter-config/realm", "addRealm", "java.lang.Object"); + + // login and error pages + digester.addCallMethod("securityfilter-config/login-config/form-login-config/form-login-page", "setLoginPage", 0); + digester.addCallMethod("securityfilter-config/login-config/form-login-config/form-error-page", "setErrorPage", 0); + digester.addCallMethod("securityfilter-config/login-config/form-login-config/form-default-page", "setDefaultPage", 0); + + // security-constraint + digester.addObjectCreate( + "securityfilter-config/security-constraint", + "org.securityfilter.config.SecurityConstraint" + ); + digester.addSetNext( + "securityfilter-config/security-constraint", + "addSecurityConstraint", + "org.securityfilter.config.SecurityConstraint" + ); + digester.addCallMethod( + "securityfilter-config/security-constraint/auth-constraint/role-name", + "addRole", + 0 + ); + + // web-resource-collection + digester.addObjectCreate( + "securityfilter-config/security-constraint/web-resource-collection", + "org.securityfilter.config.WebResourceCollection" + ); + digester.addSetNext( + "securityfilter-config/security-constraint/web-resource-collection", + "addWebResourceCollection", + "org.securityfilter.config.WebResourceCollection" + ); + digester.addCallMethod( + "securityfilter-config/security-constraint/web-resource-collection/web-resource-name", + "setName", + 0 + ); + digester.addCallMethod( + "securityfilter-config/security-constraint/web-resource-collection/url-pattern", + "addURLPattern", + 0 + ); + digester.addCallMethod( + "securityfilter-config/security-constraint/web-resource-collection/http-method", + "addHttpMethod", + 0 + ); + + InputSource input = new InputSource(configURL.openStream()); + digester.parse(input); + } +} + +// ------------------------------------------------------------------------ +// EOF \ No newline at end of file diff --git a/src/share/org/securityfilter/config/SecurityConstraint.java b/src/share/org/securityfilter/config/SecurityConstraint.java new file mode 100644 index 0000000..580476f --- /dev/null +++ b/src/share/org/securityfilter/config/SecurityConstraint.java @@ -0,0 +1,141 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/config/SecurityConstraint.java,v 1.1 2002/08/08 13:20:47 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/08/08 13:20:47 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.securityfilter.config; + +import java.util.ArrayList; +import java.util.List; + +/** + * SecurityConstraint + * + * @author Max Cooper (max@maxcooper.com) + * @author Torgeir Veimo (torgeir@pobox.com) + * @version $Revision: 1.1 $ $Date: 2002/08/08 13:20:47 $ + */ +public class SecurityConstraint { + protected String name; + protected List resourceCollections; + protected List roles; + + /** + * Constructor + */ + public SecurityConstraint() { + this.resourceCollections = new ArrayList(); + this.roles = new ArrayList(); + } + + /** + * Set the security constraint name. + * + * @param name the name of this SecurityConstraint + */ + public void setName(String name) { + this.name = name; + } + + /** + * Return the name of this SecurityConstraint + */ + public String getName() { + return this.name; + } + + /** + * Add a WebResourceCollection to this SecurityConstraint. + * + * @param resourceCollection the WebResourceCollection to add + */ + public void addWebResourceCollection(WebResourceCollection resourceCollection) { + resourceCollections.add(resourceCollection); + } + + /** + * Get the WebResourceCollections for this SecurityConstraint. The order of the list is the order in which the + * WebResourceCollections appeared in the config file. + */ + public List getWebResourceCollections() { + return this.resourceCollections; + } + + /** + * Add a role to this SecurityConstraint. + * + * @param role role to add + */ + public void addRole(String role) { + roles.add(role); + } + + /** + * Get the roles that are authorized to access the WebResourceCollections in this SecurityConstraint. + * Returns an empty list if no roles were present in the config file. + */ + public List getRoles() { + return this.roles; + } +} + +// ------------------------------------------------------------------------ +// EOF \ No newline at end of file diff --git a/src/share/org/securityfilter/config/WebResourceCollection.java b/src/share/org/securityfilter/config/WebResourceCollection.java new file mode 100644 index 0000000..3cfa88a --- /dev/null +++ b/src/share/org/securityfilter/config/WebResourceCollection.java @@ -0,0 +1,138 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/config/WebResourceCollection.java,v 1.1 2002/08/08 13:20:48 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/08/08 13:20:48 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.securityfilter.config; + +import java.util.*; + +/** + * WebResourceCollection represents a web-resource-collection from the security config file. + * It has a name, a list of url patterns, and a list of http methods. + * + * @author Max Cooper (max@maxcooper.com) + * @version $Revision: 1.1 $ $Date: 2002/08/08 13:20:48 $ + */ +public class WebResourceCollection { + protected String name; + protected List patterns; + protected Collection methods; + + /** + * Constructor + */ + public WebResourceCollection() { + patterns = Collections.synchronizedList(new ArrayList()); + methods = Collections.synchronizedSet(new HashSet()); + } + + /** + * Set the name of this WebResourceCollection. + * + * @param name name of this WebResourceCollection + */ + public void setName(String name) { + this.name = name; + } + + /** + * Get the name of this WebResourceCollection. + */ + public String getName() { + return this.name; + } + + /** + * Add a url pattern to this WebResourceCollection. + * + * @param pattern url pattern to add + */ + public void addURLPattern(String pattern) { + patterns.add(pattern); + } + + /** + * Get a list of url patterns in the order they were added to this WebResourceCollection. + */ + public List getURLPatterns() { + return Collections.unmodifiableList(patterns); + } + + /** + * Add an http method to this WebResourceCollection. + * + * @param method http method to add + */ + public void addHttpMethod(String method) { + methods.add(method); + } + + /** + * Get a collection of http methods for this WebResourceCollection. + */ + public Collection getHttpMethods() { + return Collections.unmodifiableCollection(methods); + } +} + +// ---------------------------------------------------------------------------- +// EOF \ No newline at end of file diff --git a/src/share/org/securityfilter/filter/MatchableURLPattern.java b/src/share/org/securityfilter/filter/MatchableURLPattern.java new file mode 100644 index 0000000..0bd2252 --- /dev/null +++ b/src/share/org/securityfilter/filter/MatchableURLPattern.java @@ -0,0 +1,216 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/filter/Attic/MatchableURLPattern.java,v 1.1 2002/08/08 13:20:48 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/08/08 13:20:48 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.securityfilter.filter; + +import org.apache.regexp.RE; +import org.apache.regexp.RECompiler; +import org.apache.regexp.RESyntaxException; +import org.securityfilter.config.SecurityConstraint; +import org.securityfilter.config.WebResourceCollection; + +/** + * MatchableURLPattern - Contains matchable URL pattern and the associated SecurityConstraint and WebResourceCollection + * objects for the pattern. Also supports sorting according to the Servlet Spec v2.3 (not yet implemented - just sorts + * by the order field). + * + * @author Max Cooper (max@maxcooper.com) + * @version $Revision: 1.1 $ $Date: 2002/08/08 13:20:48 $ + */ +public class MatchableURLPattern implements Comparable { + private String pattern; + private RE patternRE; + private SecurityConstraint constraint; + private WebResourceCollection resourceCollection; + private int order; + + /** + * Construct a new MatchableURLPattern object. + * + * @param pattern the url pattern to match + * @param constraint the SecurityConstraint associated with this pattern + * @param resourceCollection the WebResourceCollection associated with this pattern + * @param order the order in which this pattern occurred in the configuration file + * @param compiler an RECompiler to use to compile this url pattern + * + * @see MatchableURLPatternFactory + */ + public MatchableURLPattern( + String pattern, + SecurityConstraint constraint, + WebResourceCollection resourceCollection, + int order, + RECompiler compiler + ) throws RESyntaxException { + this.pattern = pattern; + this.constraint = constraint; + this.resourceCollection = resourceCollection; + this.order = order; + this.patternRE = new RE(compiler.compile(getConvertedPattern())); + } + + /** + * Return true if this pattern matches the passed URL. + * + * @param URL the URL to attempt to match + * @return true if this pattern matches the URL, false otherwise + */ + public boolean match(String URL) { + return patternRE.match(URL); + } + + /** + * Get the url pattern to match. + */ + public String getPattern() { + return pattern; + } + + /** + * Get the SecurityConstraint object associated with this pattern. + */ + public SecurityConstraint getSecurityConstraint() { + return constraint; + } + + /** + * Get the order value for this pattern (the order in which it appeared in the config file). + */ + public int getOrder() { + return order; + } + + /** + * Get the WebResourceCollection associated with this pattern. + */ + public WebResourceCollection getWebResourceCollection() { + return resourceCollection; + } + + /** + * Test if this pattern is equivalent to another pattern. + * This is implemented so that consistency with the compareTo method results can be maintained. + * + * @param obj the value to test equivalence with + * @return true if the passed object is an equivalent MatchableURLPattern, false if it is not a MatchableURLPattern + * or if it is not equivalent. + */ + public boolean equals(Object obj) { + if (obj instanceof MatchableURLPattern) { + MatchableURLPattern otherPattern = (MatchableURLPattern) obj; + return ( + constraint.equals(otherPattern.getSecurityConstraint()) + && resourceCollection.equals(otherPattern.getWebResourceCollection()) + && pattern.equals(otherPattern.getPattern()) + ); + } + return false; + } + + /** + * Compares this MatchableURLPattern to another to support sorting. + * Ordering is currently implemented according to the order field value, which can exhibit behavior inconsistent + * with equals() if non-equivalent instances have the same order value. + * + * TO-DO: Update to support servlet spec compliant ordering. + * + * @param o object to compare to + * + * @exception ClassCastException thrown if o is not a MatchableURLPattern instance + */ + public int compareTo(Object o) throws ClassCastException { + MatchableURLPattern otherPattern = (MatchableURLPattern) o; + if (this.equals(otherPattern)) { + return 0; + } else { + // TO-DO: update to reflect servlet spec pattern order + return (getOrder() - otherPattern.getOrder()); + } + } + + /** + * Return the pattern string in RE syntax form. + * + * TO-DO: validate that the conversion is proper for all pattern strings (probably needs some improvements). + */ + private String getConvertedPattern() { + StringBuffer buf = new StringBuffer(pattern); + int pos; + // escape '.' characters + pos = buf.toString().indexOf('.'); + while (pos != -1) { + buf.insert(pos, "\\"); + pos = buf.toString().indexOf('.', pos + 2); + } + // replace '*' chars in the pattern with '.*' + pos = buf.toString().indexOf('*'); + while (pos != -1) { + buf.replace(pos, pos + 1, ".*"); + pos = buf.toString().indexOf('*', pos + 2); + } + return buf.toString(); + } +} + +// ---------------------------------------------------------------------------- +// EOF \ No newline at end of file diff --git a/src/share/org/securityfilter/filter/MatchableURLPatternFactory.java b/src/share/org/securityfilter/filter/MatchableURLPatternFactory.java new file mode 100644 index 0000000..5db9bc4 --- /dev/null +++ b/src/share/org/securityfilter/filter/MatchableURLPatternFactory.java @@ -0,0 +1,109 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/filter/Attic/MatchableURLPatternFactory.java,v 1.1 2002/08/08 13:20:48 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/08/08 13:20:48 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.securityfilter.filter; + +import org.apache.regexp.RECompiler; +import org.apache.regexp.RESyntaxException; +import org.securityfilter.config.SecurityConstraint; +import org.securityfilter.config.WebResourceCollection; + +/** + * MatchableURLPatternFactory creates MatchableURLPattern instances. It keeps an RECompiler to use for the creation + * of a set of instances. + * + * @author Max Cooper (max@maxcooper.com) + * @version $Revision: 1.1 $ $Date: 2002/08/08 13:20:48 $ + */ +public class MatchableURLPatternFactory { + private RECompiler compiler; + + /** + * Constructor + */ + public MatchableURLPatternFactory() { + compiler = new RECompiler(); + } + + /** + * Create a MatchableURLPattern instance. + * + * @param pattern url pattern in config file syntax + * @param constraint SecurityConstraint object to associate with this pattern + * @param resourceCollection WebResourceCollection to associate with this pattern + * @param order order in which this pattern appeared in the config file + * + * @exception RESyntaxException throws exception if pattern cannot be compiled after conversion to RE syntax + */ + public MatchableURLPattern createURLPatternMatcher( + String pattern, + SecurityConstraint constraint, + WebResourceCollection resourceCollection, + int order + ) throws RESyntaxException { + return new MatchableURLPattern(pattern, constraint, resourceCollection, order, compiler); + } +} + +// ---------------------------------------------------------------------------- +// EOF \ No newline at end of file diff --git a/src/share/org/securityfilter/filter/SecurityFilter.java b/src/share/org/securityfilter/filter/SecurityFilter.java new file mode 100644 index 0000000..77ef803 --- /dev/null +++ b/src/share/org/securityfilter/filter/SecurityFilter.java @@ -0,0 +1,416 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/filter/SecurityFilter.java,v 1.1 2002/08/08 13:20:48 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/08/08 13:20:48 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.securityfilter.filter; + +import org.apache.regexp.RE; +import org.apache.regexp.RECompiler; +import org.apache.regexp.RESyntaxException; +import org.securityfilter.config.SecurityConfig; +import org.securityfilter.config.SecurityConstraint; +import org.securityfilter.config.WebResourceCollection; +import org.securityfilter.realm.SecurityRealmInterface; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; +import java.net.URL; +import java.security.Principal; +import java.util.*; + +/** + * SecurityFilter provides authentication and authorization services. + * + * @author Max Cooper (max@maxcooper.com) + * @author Torgeir Veimo (torgeir@pobox.com) + * @version $Revision: 1.1 $ $Date: 2002/08/08 13:20:48 $ + */ +public class SecurityFilter implements javax.servlet.Filter { + public static final String CONTINUE_TO_URL = SecurityFilter.class.getName() + ".CONTINUE_TO_URL"; + public static final String POSTED_PARAM_URL = SecurityFilter.class.getName() + ".POSTED_PARAM_URL"; + public static final String POSTED_PARAM_MAP = SecurityFilter.class.getName() + ".POSTED_PARAM_MAP"; + + public static final String CONFIG_FILE_KEY = "config"; + public static final String DEFAULT_CONFIG_FILE = "/WEB-INF/securityfilter-config.xml"; + public static final String VALIDATE_KEY = "validate"; + public static final String TRUE = "true"; + + protected FilterConfig config; + protected ArrayList URLPatterns; + protected SecurityRealmInterface realm; + protected String loginPage; + protected String errorPage; + protected String defaultPage; + protected RE loginSubmitRE; + protected List patternList; + + private static final String FORM_USERNAME = "j_username"; + private static final String FORM_PASSWORD = "j_password"; + private static final String FORM_SUBMIT_PATTERN = ".*/j_security_check"; + + /** + * Initialize the SecurityFilter. + * + * @param config filter configuration object + */ + public void init(FilterConfig config) { + this.config = config; + try { + // login submit RE + loginSubmitRE = new RE(new RECompiler().compile(FORM_SUBMIT_PATTERN)); + + // parse config file + String configFile = config.getInitParameter(CONFIG_FILE_KEY); + if (configFile == null) { + configFile = DEFAULT_CONFIG_FILE; + } + URL configURL = config.getServletContext().getResource(configFile); + String validate = config.getInitParameter(VALIDATE_KEY); + SecurityConfig securityConfig = new SecurityConfig(TRUE.equalsIgnoreCase(validate)); + securityConfig.loadConfig(configURL); + + // get config values + realm = securityConfig.getRealm(); + errorPage = securityConfig.getErrorPage(); + loginPage = securityConfig.getLoginPage(); + defaultPage = securityConfig.getDefaultPage(); + + // create pattern list + patternList = new ArrayList(); + MatchableURLPatternFactory patternFactory = new MatchableURLPatternFactory(); + int order = 1; + List constraints = securityConfig.getSecurityConstraints(); + for (Iterator cIter = constraints.iterator(); cIter.hasNext();) { + SecurityConstraint constraint = (SecurityConstraint) cIter.next(); + for (Iterator rIter = constraint.getWebResourceCollections().iterator(); rIter.hasNext();) { + WebResourceCollection resourceCollection = (WebResourceCollection) rIter.next(); + for (Iterator pIter = resourceCollection.getURLPatterns().iterator(); pIter.hasNext();) { + MatchableURLPattern pattern = patternFactory.createURLPatternMatcher( + (String) pIter.next(), + constraint, + resourceCollection, + order++ + ); + patternList.add(pattern); + } + } + } + Collections.sort(patternList); + + } catch (RESyntaxException rese) { + System.err.println("invalid regular expression pattern: " + rese); + } catch (java.io.IOException ioe) { + System.err.println("unable to parse input: " + ioe); + } catch (org.xml.sax.SAXException se) { + System.err.println("unable to parse input: " + se); + } + } + + /** + * Destroy the filter, releasing resources. + */ + public void destroy() { + } + + /** + * Set the filter configuration, included for WebLogic 6 compatibility. + * + * @param config filter configuration object + */ + public void setFilterConfig(FilterConfig config) { + init(config); + } + + /** + * Get the filter config object, included for WebLogic 6 compatibility. + */ + public FilterConfig getFilterConfig() { + return config; + } + + /** + * Perform filtering operation, and optionally pass the request down the chain. + * + * @param request the current request + * @param response the current response + * @param chain request handler chain + * @exception IOException + * @exception ServletException + */ + public void doFilter( + ServletRequest request, + ServletResponse response, + FilterChain chain + ) throws IOException, ServletException { + + HttpServletRequest hReq = (HttpServletRequest) request; + HttpServletResponse hRes = (HttpServletResponse) response; + SecurityRequestWrapper wrappedRequest; + + // if the request has already been wrapped by the filter, pass it through unchecked + if (request instanceof SecurityRequestWrapper) { + wrappedRequest = (SecurityRequestWrapper) request; + } else { + // extract the request URL portion that needs to be checked + String requestURL = hReq.getRequestURI(); + // remove the contextPath + requestURL = requestURL.substring(hReq.getContextPath().length()); + + String pathInfo = hReq.getPathInfo(); + if ("/".equals(requestURL) && pathInfo != null) { + requestURL = pathInfo; + } + + // get posted parameter map, if any (returns null if not applicable) + Map parameterMap = getPostedParameterMap(hReq); + + // wrap request + wrappedRequest = new SecurityRequestWrapper(hReq, realm, parameterMap); + + // check if this is a login form submittal + if (loginSubmitRE.match(requestURL)) { + processLogin(wrappedRequest, hRes); + return; + } + + // check if request matches security constraint + MatchableURLPattern match = matchPattern(requestURL); + + // check constraint, if any + if (match != null) { + // check roles + Collection roles = match.getSecurityConstraint().getRoles(); + if (!roles.isEmpty()) { + Principal principal = wrappedRequest.getUserPrincipal(); + if (principal == null) { + // user needs to be authenticated + showLogin(hReq, hRes); + return; + } else { + boolean authorized = false; + for (Iterator i = roles.iterator(); i.hasNext() && !authorized;) { + String role = (String) i.next(); + if ("*".equals(role) || realm.isUserInRole(principal, role)) { + authorized = true; + } + } + if (!authorized) { + // user does not meet role constraint + hRes.sendError(HttpServletResponse.SC_FORBIDDEN); + return; + } + } + } + } + } + + // pass the request down the filter chain + chain.doFilter(wrappedRequest, hRes); + } + + /** + * Find a match for the requested URL, if any. + * + * @param URL the URL to match + * @return the matching MatchableURLPattern object, or null if there is no match. + */ + protected MatchableURLPattern matchPattern(String URL) { + // PERFORMANCE IMPROVEMENT OPPORTUNITY: cahce URL pattern matches + MatchableURLPattern pattern = null; + for (Iterator i = patternList.iterator(); i.hasNext() && (pattern == null);) { + MatchableURLPattern testPattern = (MatchableURLPattern) i.next(); + if (testPattern.match(URL)) { + pattern = testPattern; + } + } + return pattern; + } + + /** + * Show the login page. + * + * @param request the current request + * @param response the current response + * @exception IOException + * @exception ServletException + */ + protected void showLogin( + HttpServletRequest request, + HttpServletResponse response + ) throws IOException, ServletException { + // save continue to URL + setContinueToURL(request); + // if this is a post, save request parameters + if (request.getMethod().equalsIgnoreCase("POST")) { + setIncludePostedParametersForThisURL(request); + } + // forward to login page + request.getRequestDispatcher(loginPage).forward(request, response); + } + + /** + * Process a login form submittal. + * + * @param request the current request + * @param response the current response + * @exception IOException + * @exception ServletException + */ + protected void processLogin( + SecurityRequestWrapper request, + HttpServletResponse response + ) throws IOException, ServletException { + String username = request.getParameter(FORM_USERNAME); + String password = request.getParameter(FORM_PASSWORD); + Principal principal = realm.authenticate(username, password); + if (principal != null) { + // login successful + request.setUserPrincipal(principal); + String continueToURL = getAndClearContinueToURL(request); + response.sendRedirect(continueToURL); + } else { + // login failed, set response status and forward to error page + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + request.getRequestDispatcher(errorPage).forward(request, response); + } + } + + /** + * Get the URL to continue to after successful login from the session, and then remove it from the session. + * + * @param request the current request + */ + protected String getAndClearContinueToURL(HttpServletRequest request) { + HttpSession session = request.getSession(true); + String continueToURL = (String) session.getAttribute(CONTINUE_TO_URL); + if (continueToURL == null) { + return request.getContextPath() + defaultPage; + } else { + session.removeAttribute(CONTINUE_TO_URL); + return continueToURL; + } + } + + /** + * Save the current URL and POSTed parameters. + * + * @param request the current request + */ + protected void setIncludePostedParametersForThisURL(HttpServletRequest request) { + HttpSession session = request.getSession(true); + session.setAttribute(SecurityFilter.POSTED_PARAM_URL, request.getRequestURL().toString()); + session.setAttribute(SecurityFilter.POSTED_PARAM_MAP, request.getParameterMap()); + } + + /** + * If this request matches the one we saved POSTed parameters, return a map of those parameters and remove this + * associated information (URL + parameter map) from the session). + * + * @param request the current request + * @return usually null, but when the request matches the posted URL that initiated the login sequence a map + * of the request parameters from the original post is returned + */ + protected Map getPostedParameterMap(HttpServletRequest request) { + HttpSession session = request.getSession(true); + String postedURL = (String) session.getAttribute(SecurityFilter.POSTED_PARAM_URL); + if (postedURL != null && postedURL.equals(request.getRequestURL().toString())) { + // this is a request for the post that caused the login, + // return the map of posted params and remove it from the session + Map map = (Map) session.getAttribute(SecurityFilter.POSTED_PARAM_MAP); + session.removeAttribute(SecurityFilter.POSTED_PARAM_URL); + session.removeAttribute(SecurityFilter.POSTED_PARAM_MAP); + return map; + } else { + return null; + } + } + + /** + * Save the current URL in the session so that we can redirect to this URL upon successful login. + * This method will not save the URL if it matches the login page, login error page, or login submit URL. + * + * @param request the current HttpServletRequest + */ + protected void setContinueToURL(HttpServletRequest request) { + // only save if it isn't the login page, login error page, or the login submit URL + String currentURL = request.getServletPath(); + if ( + !loginSubmitRE.match(currentURL) + && !loginPage.equals(currentURL) + && !errorPage.equals(currentURL) + ) { + StringBuffer continueToURL = new StringBuffer(request.getRequestURI()); + + String queryString = request.getQueryString(); + if (queryString != null) { + continueToURL.append("?" + queryString); + } + request.getSession().setAttribute(CONTINUE_TO_URL, continueToURL.toString()); + } + } +} + +// ------------------------------------------------------------------------ +// EOF \ No newline at end of file diff --git a/src/share/org/securityfilter/filter/SecurityRequestWrapper.java b/src/share/org/securityfilter/filter/SecurityRequestWrapper.java new file mode 100644 index 0000000..b4358a9 --- /dev/null +++ b/src/share/org/securityfilter/filter/SecurityRequestWrapper.java @@ -0,0 +1,235 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/filter/SecurityRequestWrapper.java,v 1.1 2002/08/08 13:20:48 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/08/08 13:20:48 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.securityfilter.filter; + +import org.securityfilter.realm.SecurityRealmInterface; + +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.IOException; +import java.security.Principal; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * SecurityRequestWrapper + * + * @author Max Cooper (max@maxcooper.com) + * @author Torgeir Veimo (torgeir@pobox.com) + * @version $Revision: 1.1 $ $Date: 2002/08/08 13:20:48 $ + */ +public class SecurityRequestWrapper extends HttpServletRequestWrapper { + public static final String PRINCIPAL_SESSION_KEY = SecurityRequestWrapper.class.getName() + ".PRINCIPAL"; + + private HttpServletRequest request; + private SecurityRealmInterface realm; + private Map postedParameterMap; + + /** + * Construct a new SecurityRequestWrapper. + * + * @param request the request to wrap + * @param realm the SecurityRealmInterface implementation + * @param postedParameterMap map of name-value pairs to present as request parameters (POSTed params from a previous + * request) + */ + public SecurityRequestWrapper(HttpServletRequest request, SecurityRealmInterface realm, Map postedParameterMap) { + super(request); + this.request = request; + this.realm = realm; + this.postedParameterMap = postedParameterMap; + } + + /** + * Get a parameter value by name. If multiple values are available, the first value is returned. + * + * @param s parameter name + */ + public String getParameter(String s) { + if (postedParameterMap == null) { + return request.getParameter(s); + } else { + String value = request.getParameter(s); + if (value == null) { + String[] valueArray = (String[]) postedParameterMap.get(s); + if (valueArray != null) { + value = valueArray[0]; + } + } + return value; + } + } + + /** + * Get a map of parameter values for this request. + */ + public Map getParameterMap() { + if (postedParameterMap == null) { + return request.getParameterMap(); + } else { + Map map = new HashMap(postedParameterMap); + map.putAll(request.getParameterMap()); + return Collections.unmodifiableMap(map); + } + } + + /** + * Get an enumeration of paramaeter names for this request. + */ + public Enumeration getParameterNames() { + if (postedParameterMap == null) { + return request.getParameterNames(); + } else { + return Collections.enumeration(getParameterMap().keySet()); + } + } + + /** + * Get an array of values for a parameter. + * + * @param s parameter name + */ + public String[] getParameterValues(String s) { + if (postedParameterMap == null) { + return request.getParameterValues(s); + } else { + String[] values = request.getParameterValues(s); + if (values == null) { + values = (String[]) postedParameterMap.get(s); + } + return values; + } + } + + /** + * Set the request that is to be wrapped. + * + * @param request wrap this request + */ + public void setRequest(ServletRequest request) { + super.setRequest(request); + this.request = (HttpServletRequest) request; + } + + /** + * Check if a user is in a role. + * + * @param role name of role to check + */ + public boolean isUserInRole(String role) { + return realm.isUserInRole(getUserPrincipal(), role); + } + + /** + * Get the remote user's login name + */ + public String getRemoteUser() { + String username = null; + Principal principal = getUserPrincipal(); + if (principal != null) { + username = principal.getName(); + } + return username; + } + + /** + * Get a Principal object for the current user. + */ + public Principal getUserPrincipal() { + return (Principal) request.getSession().getAttribute(PRINCIPAL_SESSION_KEY); + } + + /** + * This method is provided to restore functionality of this method in case the wrapper class we are extending + * has disabled it. This method is needed to process multi-part requests downstream, and it appears that some + * wrapper implementations just return null. WebLogic 6.1.2.0 is one such implementation. + * + * @exception IOException + */ + public ServletInputStream getInputStream() throws IOException { + ServletInputStream stream = super.getInputStream(); + if (stream == null) { + stream = request.getInputStream(); + } + return stream; + } + + /** + * Set the username of the current user. + * WARNING: Calling this method will set the user for this session -- authenticate the user before calling + * this method. + * + * @param username the login name of the remote user for this session + */ + public void setUserPrincipal(Principal principal) { + request.getSession().setAttribute(PRINCIPAL_SESSION_KEY, principal); + } +} + +// ------------------------------------------------------------------------ +// EOF \ No newline at end of file diff --git a/src/share/org/securityfilter/realm/SecurityRealmBase.java b/src/share/org/securityfilter/realm/SecurityRealmBase.java new file mode 100644 index 0000000..81580e6 --- /dev/null +++ b/src/share/org/securityfilter/realm/SecurityRealmBase.java @@ -0,0 +1,135 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/realm/Attic/SecurityRealmBase.java,v 1.1 2002/08/08 13:20:48 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/08/08 13:20:48 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.securityfilter.realm; + +import java.security.Principal; + +/** + * SecurityRealmBase - abstract security realm base class. This class insulates you from having + * to create or process Principal objects. You can implement a realm by implementing the two methods + * that neither take or return a Principal object and this class does the conversions for you. + * + * @author Max Cooper (max@maxcooper.com) + */ +public abstract class SecurityRealmBase implements SecurityRealmInterface { + + /** + * Authenticate a user. + * + * Implement this method in a subclass to avoid dealing with Principal objects. + * + * @param username a username + * @param password a plain text password, as entered by the user + * + * @return null if the user cannot be authenticated, otherwise a Pricipal object is returned + */ + public abstract boolean booleanAuthenticate(String username, String password); + + /** + * Test for role membership. + * + * Implement this method in a subclass to avoid dealing with Principal objects. + * + * @param principal Principal object representing a user + * @param rolename name of a role to test for membership + * @return true if the user is in the role, false otherwise + */ + public abstract boolean isUserInRole(String username, String rolename); + + /** + * Authenticate a user. + * + * @param username a username + * @param password a plain text password, as entered by the user + * + * @return a Principal object representing the user if successful, false otherwise + */ + public Principal authenticate(final String username, String password) { + if (booleanAuthenticate(username, password)) { + return new Principal() { + public String getName() { + return username; + } + }; + } else { + return null; + } + } + + /** + * Test for role membership. + * + * Use Principal.getName() to get the username from the principal object. + * + * @param principal Principal object representing a user + * @param rolename name of a role to test for membership + * @return true if the user is in the role, false otherwise + */ + public boolean isUserInRole(Principal principal, String rolename) { + return isUserInRole(principal.getName(), rolename); + } +} + +// ---------------------------------------------------------------------------- +// EOF \ No newline at end of file diff --git a/src/share/org/securityfilter/realm/SecurityRealmInterface.java b/src/share/org/securityfilter/realm/SecurityRealmInterface.java new file mode 100644 index 0000000..03bb791 --- /dev/null +++ b/src/share/org/securityfilter/realm/SecurityRealmInterface.java @@ -0,0 +1,102 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/realm/SecurityRealmInterface.java,v 1.1 2002/08/08 13:20:48 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/08/08 13:20:48 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.securityfilter.realm; + +import java.security.Principal; + +/** + * SecurityRealmInterface - realm interface for SecurityFilter. Implement this interface to provide + * a realm implementation against which SecurityFilter can authenticate and authortize users. + * + * Typically, a project will implement this interface or adapt an existing realm implementation to this interface. + * + * @author Max Cooper (max@maxcooper.com) + * @version $Revision: 1.1 $ $Date: 2002/08/08 13:20:48 $ + */ +public interface SecurityRealmInterface { + + /** + * Authenticate a user. + * + * @param username a username + * @param password a plain text password, as entered by the user + * + * @return a Principal object representing the user if successful, false otherwise + */ + public Principal authenticate(String username, String password); + + /** + * Test for role membership. + * + * Use Principal.getName() to get the username from the principal object. + * + * @param principal Principal object representing a user + * @param rolename name of a role to test for membership + * @return true if the user is in the role, false otherwise + */ + public boolean isUserInRole(Principal principal, String rolename); +} + +// ------------------------------------------------------------------------ +// EOF \ No newline at end of file diff --git a/src/share/org/securityfilter/realm/adapter/CatalinaRealmAdapter.java b/src/share/org/securityfilter/realm/adapter/CatalinaRealmAdapter.java new file mode 100644 index 0000000..595108f --- /dev/null +++ b/src/share/org/securityfilter/realm/adapter/CatalinaRealmAdapter.java @@ -0,0 +1,113 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/realm/adapter/Attic/CatalinaRealmAdapter.java,v 1.1 2002/08/08 13:20:48 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/08/08 13:20:48 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.securityfilter.realm.adapter; + +import org.apache.catalina.Realm; +import org.securityfilter.realm.SecurityRealmInterface; + +import java.security.Principal; + +/** + * CatalinaRealmAdapter - adapts a Catalina Realm for use with the securityfilter + * + * @author Max Cooper (max@maxcooper.com) + */ +public class CatalinaRealmAdapter implements SecurityRealmInterface { + private Realm realm; + + /** + * Set the Catalina Realm that we are to adapt. + */ + public void setRealm(Object realm) { + this.realm = (Realm) realm; + } + + /** + * Authenticate a user. + * + * @param username a username + * @param password a plain text password, as entered by the user + * + * @return a Principal object representing the user if successful, false otherwise + */ + public Principal authenticate(String username, String password) { + return realm.authenticate(username, password); + } + + /** + * Test for role membership. + * + * Use Principal.getName() to get the username from the principal object. + * + * @param principal Principal object representing a user + * @param rolename name of a role to test for membership + * @return true if the user is in the role, false otherwise + */ + public boolean isUserInRole(Principal principal, String rolename) { + return realm.hasRole(principal, rolename); + } +} + +// ---------------------------------------------------------------------------- +// EOF \ No newline at end of file diff --git a/web/blank/WEB-INF/securityfilter-config.xml b/web/blank/WEB-INF/securityfilter-config.xml new file mode 100644 index 0000000..e4ebe43 --- /dev/null +++ b/web/blank/WEB-INF/securityfilter-config.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/blank/WEB-INF/web.xml b/web/blank/WEB-INF/web.xml new file mode 100644 index 0000000..d181163 --- /dev/null +++ b/web/blank/WEB-INF/web.xml @@ -0,0 +1,30 @@ + + + + + + + + Security Filter + org.securityfilter.filter.SecurityFilter + + config + /WEB-INF/securityfilter-config.xml + Configuration file location (this is the default value) + + + validate + true + Validate config file if set to true + + + + + + Security Filter + /* + + + diff --git a/web/catalina-example/WEB-INF/securityfilter-config.xml b/web/catalina-example/WEB-INF/securityfilter-config.xml new file mode 100644 index 0000000..1dc48ad --- /dev/null +++ b/web/catalina-example/WEB-INF/securityfilter-config.xml @@ -0,0 +1,45 @@ + + + + + + + + + Secure Page + /securePage.jsp + + + inthisrole + + + + + + Secure page that the example user is not authorized to view + /forbiddenPage.jsp + + + notinthisrole + + + + + + /loginForm.jsp + /loginError.jsp + /index.jsp + + + + + + + + + + + + \ No newline at end of file diff --git a/web/example/WEB-INF/securityfilter-config.xml b/web/example/WEB-INF/securityfilter-config.xml new file mode 100644 index 0000000..b4f5a5b --- /dev/null +++ b/web/example/WEB-INF/securityfilter-config.xml @@ -0,0 +1,41 @@ + + + + + + + + + Secure Page + /securePage.jsp + + + inthisrole + + + + + + Secure page that the example user is not authorized to view + /forbiddenPage.jsp + + + notinthisrole + + + + + + /loginForm.jsp + /loginError.jsp + /index.jsp + + + + + + + + \ No newline at end of file diff --git a/web/share/WEB-INF/web.xml b/web/share/WEB-INF/web.xml new file mode 100644 index 0000000..a094913 --- /dev/null +++ b/web/share/WEB-INF/web.xml @@ -0,0 +1,45 @@ + + + + + + + + Security Filter + org.securityfilter.filter.SecurityFilter + + config + /WEB-INF/securityfilter-config.xml + Configuration file location (this is the default value) + + + validate + true + Validate config file if set to true + + + + + + Security Filter + /* + + + + + 1 + + + + /index.jsp + + + + + 403 + /error/403.jsp + + + diff --git a/web/share/error/403.jsp b/web/share/error/403.jsp new file mode 100644 index 0000000..12baf95 --- /dev/null +++ b/web/share/error/403.jsp @@ -0,0 +1,10 @@ + + +SecurityFilter Example Application: Forbidden + + +

SecurityFilter Example Application: Forbidden

+<%@include file="/menu.jsp" %> +Error 403: You are not authorized to view the requested resource. + + \ No newline at end of file diff --git a/web/share/forbiddenPage.jsp b/web/share/forbiddenPage.jsp new file mode 100644 index 0000000..45cfd96 --- /dev/null +++ b/web/share/forbiddenPage.jsp @@ -0,0 +1,9 @@ + + +SecurityFilter Example Application: Forbidden Secure Page + + +

SecurityFilter Example Application: Forbidden Secure Page

+<%@include file="/menu.jsp" %> +Welcome <%=request.getRemoteUser()%>, you are viewing a secure page. But something went wrong because you aren't authorized to see it! + \ No newline at end of file diff --git a/web/share/index.jsp b/web/share/index.jsp new file mode 100644 index 0000000..35b27e8 --- /dev/null +++ b/web/share/index.jsp @@ -0,0 +1,10 @@ + + +SecurityFilter Example Application: Home + + +

SecurityFilter Example Application: Home

+<%@include file="/menu.jsp" %> +Welcome to the Security Filter example application. Use the menu above to navigate the site. + + \ No newline at end of file diff --git a/web/share/loginError.jsp b/web/share/loginError.jsp new file mode 100644 index 0000000..7eecc0b --- /dev/null +++ b/web/share/loginError.jsp @@ -0,0 +1,10 @@ + + +SecurityFilter Example Application: Login Error Page + + +

SecurityFilter Example Application: Login Error Page

+<%@include file="/menu.jsp" %> +Bad username/password combination, please try again. + + \ No newline at end of file diff --git a/web/share/loginForm.jsp b/web/share/loginForm.jsp new file mode 100644 index 0000000..ec51c95 --- /dev/null +++ b/web/share/loginForm.jsp @@ -0,0 +1,15 @@ + + +SecurityFilter Example Application: Login Form + + +

SecurityFilter Example Application: Login Form

+<%@include file="/menu.jsp" %> +Login with username=username and password=password. +
+Username:

+Password:

+ +

+ + \ No newline at end of file diff --git a/web/share/logout.jsp b/web/share/logout.jsp new file mode 100644 index 0000000..9709ec0 --- /dev/null +++ b/web/share/logout.jsp @@ -0,0 +1,12 @@ + + +SecurityFilter Example Application: Logout + + +

SecurityFilter Example Application: Logout

+<%@include file="/menu.jsp" %> +<% session.invalidate(); %> +You have been logged out of the SecurityFilter example application.

+This operation was achieved with a simple call to session.invalidate(). + + \ No newline at end of file diff --git a/web/share/menu.jsp b/web/share/menu.jsp new file mode 100644 index 0000000..3ec9a6f --- /dev/null +++ b/web/share/menu.jsp @@ -0,0 +1,8 @@ +

+Navigation Menu: [ +Home +| Secure Page +| Forbidden Secure Page +| Direct Login +| Logout +]

diff --git a/web/share/securePage.jsp b/web/share/securePage.jsp new file mode 100644 index 0000000..6a612d5 --- /dev/null +++ b/web/share/securePage.jsp @@ -0,0 +1,9 @@ + + +SecurityFilter Example Application: Secure Page + + +

SecurityFilter Example Application: Secure Page

+<%@include file="/menu.jsp" %> +Welcome <%=request.getRemoteUser()%>, you are viewing a secure page. + \ No newline at end of file