From: <mol...@us...> - 2008-12-03 16:07:10
|
Revision: 931 http://openutils.svn.sourceforge.net/openutils/?rev=931&view=rev Author: molaschi Date: 2008-12-03 16:06:59 +0000 (Wed, 03 Dec 2008) Log Message: ----------- add openutils mgnlcas module Modified Paths: -------------- trunk/pom.xml Added Paths: ----------- trunk/openutils-mgnlcas/ trunk/openutils-mgnlcas/pom.xml trunk/openutils-mgnlcas/src/ trunk/openutils-mgnlcas/src/main/ trunk/openutils-mgnlcas/src/main/java/ trunk/openutils-mgnlcas/src/main/java/info/ trunk/openutils-mgnlcas/src/main/java/info/magnolia/ trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/ trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/security/ trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/security/auth/ trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/security/auth/callback/ trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/security/auth/callback/CompositeCallback.java trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/util/ trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/util/PatternDelegate.java trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/util/UrlPatternDelegate.java trunk/openutils-mgnlcas/src/main/java/net/ trunk/openutils-mgnlcas/src/main/java/net/sourceforge/ trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/ trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/ trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CASAuthenticationModule.java trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CasClientCallback.java trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CasLogin.java trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CasMagnoliaUser.java trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/RequestUtils.java trunk/openutils-mgnlcas/src/main/resources/ trunk/openutils-mgnlcas/src/site/ Added: trunk/openutils-mgnlcas/pom.xml =================================================================== --- trunk/openutils-mgnlcas/pom.xml (rev 0) +++ trunk/openutils-mgnlcas/pom.xml 2008-12-03 16:06:59 UTC (rev 931) @@ -0,0 +1,79 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <parent> + <groupId>net.sourceforge.openutils</groupId> + <artifactId>openutils</artifactId> + <version>10</version> + <relativePath>..</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + <packaging>jar</packaging> + <artifactId>openutils-cas</artifactId> + <name>openutils-cas</name> + <version>1.0-SNAPSHOT</version> + <licenses> + <license> + <name>GPLv3</name> + <url>http://www.gnu.org/licenses/gpl-3.0.txt</url> + </license> + </licenses> + <build> + <resources> + <resource> + <filtering>false</filtering> + <directory>src/main/resources</directory> + <includes> + <include>**/*</include> + </includes> + </resource> + <resource> + <filtering>true</filtering> + <directory>src/main/resources</directory> + <includes> + <include>META-INF/magnolia/*</include> + </includes> + </resource> + </resources> + </build> + <dependencies> + <dependency> + <groupId>info.magnolia</groupId> + <artifactId>magnolia-jaas</artifactId> + <version>3.6.3</version> + </dependency> + <dependency> + <groupId>org.jasig.cas</groupId> + <artifactId>cas-client-core</artifactId> + <version>3.1.3</version> + <exclusions> + <exclusion> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + </exclusion> + </exclusions> + </dependency> + </dependencies> + <repositories> + <repository> + <id>repository.magnolia.info</id> + <name>magnolia repository</name> + <url>http://svn.magnolia.info/maven/m2</url> + <releases> + <enabled>true</enabled> + </releases> + <snapshots> + <enabled>false</enabled> + </snapshots> + </repository> + <repository> + <id>jasig-repository</id> + <name>JA-SIG Maven2 Repository</name> + <url>http://developer.ja-sig.org/maven2</url> + <releases> + <enabled>true</enabled> + </releases> + <snapshots> + <enabled>false</enabled> + </snapshots> + </repository> + </repositories> +</project> Added: trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/security/auth/callback/CompositeCallback.java =================================================================== --- trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/security/auth/callback/CompositeCallback.java (rev 0) +++ trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/security/auth/callback/CompositeCallback.java 2008-12-03 16:06:59 UTC (rev 931) @@ -0,0 +1,115 @@ +// DONE in magnolia 3.6.2 +/** + * This file Copyright (c) 2003-2008 Magnolia International + * Ltd. (http://www.magnolia.info). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia.info/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.cms.security.auth.callback; + +import info.magnolia.cms.util.PatternDelegate; +import info.magnolia.cms.util.UrlPatternDelegate; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.ArrayUtils; + + +/** + * <p> + * A simple "composite" callback that delegates to other callbacks based on rules (a list of {@link PatternDelegate}). + * </p> + * <p> + * It can be used to configured different callbacks for different urls, see this sample configuration for an example: + * </p> + * + * <pre> + * + clientCallback + * + patterns + * + admin + * + delegate + * - class info.magnolia.cms.security.auth.callback.FormClientCallback + * - loginForm /mgnl-resources/loginForm/login.html + * - realmName Magnolia + * - class info.magnolia.cms.util.UrlPatternDelegate + * - url ./magnolia* + * + public + * + delegate + * - class info.magnolia.cms.security.auth.callback.FormClientCallback + * - loginForm /mgnl-resources/public-login.html + * - realmName Magnolia + * - class info.magnolia.cms.util.UrlPatternDelegate + * - url /* + * - class info.magnolia.cms.security.auth.callback.CompositeCallback + * </pre> + * @author fgiust + * @version $Id: CompositeCallback.java 4124 2008-09-22 14:56:46Z fgiust $ + */ +public class CompositeCallback implements HttpClientCallback +{ + + private PatternDelegate[] patterns = new UrlPatternDelegate[0]; + + /** + * Delegates the processing to the first matching Callback in patterns. + * @param request HttpServletRequest + * @param response HttpServletResponse + */ + public void handle(HttpServletRequest request, HttpServletResponse response) + { + for (int i = 0; i < patterns.length; i++) + { + PatternDelegate currentPattern = patterns[i]; + if (currentPattern.match(request)) + { + ((HttpClientCallback) currentPattern.getDelegate()).handle(request, response); + break; + } + } + } + + /** + * @return array of configured PatternDelegate. + */ + public PatternDelegate[] getPatterns() + { + return this.patterns; + } + + /** + * Adds a new PatternDelegate. Used by Content2Bean . + * @param pattern PatternDelegate instance + */ + public void addPattern(PatternDelegate pattern) + { + this.patterns = (PatternDelegate[]) ArrayUtils.add(this.patterns, pattern); + } +} \ No newline at end of file Added: trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/util/PatternDelegate.java =================================================================== --- trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/util/PatternDelegate.java (rev 0) +++ trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/util/PatternDelegate.java 2008-12-03 16:06:59 UTC (rev 931) @@ -0,0 +1,62 @@ +// DONE in magnolia 3.6.2 +/** + * This file Copyright (c) 2003-2008 Magnolia International + * Ltd. (http://www.magnolia.info). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia.info/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.cms.util; + +import javax.servlet.http.HttpServletRequest; + + +/** + * A simple generic interface that can be used to configure anything that can be selected based on some conditions (i.e. + * a different login page based on the request URI or host). + * @author fgiust + * @version $Id: PatternDelegate.java 4124 2008-09-22 14:56:46Z fgiust $ + */ +public interface PatternDelegate +{ + + /** + * Does the current request match the expected condition? + * @param request HttpServletRequest + * @return <code>true</code> if the current request matches the expected conditions + */ + boolean match(HttpServletRequest request); + + /** + * Returns the delegate that this bean holds. This method is usually called to retrieve the delegate object after + * match() returns true. + * @return delegate object + */ + Object getDelegate(); +} Added: trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/util/UrlPatternDelegate.java =================================================================== --- trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/util/UrlPatternDelegate.java (rev 0) +++ trunk/openutils-mgnlcas/src/main/java/info/magnolia/cms/util/UrlPatternDelegate.java 2008-12-03 16:06:59 UTC (rev 931) @@ -0,0 +1,153 @@ +// DONE in magnolia 3.6.2 +/** + * This file Copyright (c) 2003-2008 Magnolia International + * Ltd. (http://www.magnolia.info). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia.info/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.cms.util; + +import info.magnolia.context.MgnlContext; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; + + +/** + * An implementation of {@link PatternDelegate} that evaluates as condition a request uri patter or a hostname pattern. + * @author fgiust + * @version $Id: UrlPatternDelegate.java 4124 2008-09-22 14:56:46Z fgiust $ + */ +public class UrlPatternDelegate implements PatternDelegate +{ + + private String url; + + private SimpleUrlPattern urlPattern; + + private String host; + + private SimpleUrlPattern hostPattern; + + private Object delegate; + + /** + * The configured Url + * @return the configured Url + */ + public String getUrl() + { + return url; + } + + /** + * Sets the Url pattern (using {@link SimpleUrlPattern} internally) + * @param pattern url pattern + */ + public void setUrl(String pattern) + { + this.url = pattern; + this.urlPattern = new SimpleUrlPattern(pattern); + } + + /** + * The configured host + * @return the configured host + */ + public String getHost() + { + return host; + } + + /** + * Sets the host pattern (using {@link SimpleUrlPattern} internally) + * @param host host pattern + */ + public void setHost(String host) + { + this.host = host; + this.hostPattern = new SimpleUrlPattern(host); + } + + /** + * Compares the reques with the url and host patterns + * @param request HttpServletRequest + * @return <code>true</code> if the pattern matches the configured host (if set) and url (if set) + */ + public boolean match(HttpServletRequest request) + { + + boolean match = true; + + if (hostPattern != null) + { + match = hostPattern.match(request.getServerName()); + } + + if (urlPattern != null) + { + match = urlPattern.match(MgnlContext.getAggregationState().getCurrentURI()); + } + + return match; + } + + /** + * Sets the delegate. + * @param delegate the delegate to set + */ + public void setDelegate(Object delegate) + { + this.delegate = delegate; + } + + /** + * Returns the delegate. + * @return the delegate + */ + public Object getDelegate() + { + return delegate; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() + { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("url", this.url).append( + "host", + this.host).toString(); + } + +} \ No newline at end of file Added: trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CASAuthenticationModule.java =================================================================== --- trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CASAuthenticationModule.java (rev 0) +++ trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CASAuthenticationModule.java 2008-12-03 16:06:59 UTC (rev 931) @@ -0,0 +1,412 @@ +/** + * Copyright Openmind http://www.openmindonline.it + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +package net.sourceforge.openutils.mgnlcas; + +import info.magnolia.cms.security.User; +import info.magnolia.cms.security.auth.Entity; +import info.magnolia.cms.security.auth.GroupList; +import info.magnolia.cms.security.auth.RoleList; +import info.magnolia.cms.security.auth.callback.RealmCallback; +import info.magnolia.cms.util.BooleanUtil; +import info.magnolia.jaas.principal.EntityImpl; +import info.magnolia.jaas.principal.GroupListImpl; +import info.magnolia.jaas.principal.RoleListImpl; +import info.magnolia.jaas.sp.AbstractLoginModule; +import info.magnolia.jaas.sp.UserAwareLoginModule; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.TextInputCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.LoginException; +import javax.security.auth.spi.LoginModule; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.jasig.cas.client.authentication.AttributePrincipal; +import org.jasig.cas.client.validation.Assertion; +import org.jasig.cas.client.validation.Cas20ProxyTicketValidator; +import org.jasig.cas.client.validation.TicketValidationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * This class implements a JAAS <code>LoginModule</code> that defers authentication to CAS. See the <a + * href="http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASRefGuide.html"> JAAS documentation</a> for details + * about configuration and architecture. + * <p> + * The calling application's <code>CallbackHandler</code> MUST return the <strong>ticket</strong> for a + * <code>TextInputCallback</code> whose prompt is "ticket". + * <p> + * The CAS <strong>service</strong> MAY be hard-coded into the configuration; if it is not, the calling application's + * <code>CallbackHandler</code> MAY return the <strong>service</strong> in a <code>TextInputCallback</code> whose prompt + * is "service". + * <p> + * The <strong>cas_validate_url</strong> MUST be hard-coded in the configuration + * <p> + * Sample jaas.config configuration: + * </p> + * + * <pre> + * magnolia { + * net.sourceforge.openutils.mgnlcas.CASAuthenticationModule + * requisite + * realm=cas; + * info.magnolia.jaas.sp.jcr.JCRAuthenticationModule + * requisite + * skip_on_previous_success=true; + * info.magnolia.jaas.sp.jcr.JCRAuthorizationModule required; + * }; + * + * + * </pre> + * @author fgiust + * @version $Id: CASAuthenticationModule.java 4124 2008-09-22 14:56:46Z fgiust $ + */ +public class CASAuthenticationModule extends AbstractLoginModule implements LoginModule, UserAwareLoginModule +{ + + protected Subject subject; + + protected CallbackHandler callbackHandler; + + protected String casValidateUrl; + + protected String service; + + protected AttributePrincipal principal; + + protected User user; + + private boolean skipOnPreviousSuccess; + + private String defaultGroup; + + private String defaultRole; + + private String rolesAttribute = "roles"; + + private String groupsAttribute = "groups"; + + protected Logger log = LoggerFactory.getLogger(getClass()); + + /** + * @param subject + * @param callbackHandler + * @param sharedState + * @param options can contain + * <ul> + * <li><strong>cas_validate_url</strong> (required)</li> + * <li><strong>service</strong> (optional)</li> + * </ul> + */ + @Override + public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) + { + super.initialize(subject, callbackHandler, sharedState, options); + this.subject = subject; + this.callbackHandler = callbackHandler; + this.casValidateUrl = (String) options.get("cas_validate_url"); + this.service = (String) options.get("service"); + this.defaultGroup = (String) options.get("default_group"); + this.defaultRole = (String) options.get("default_role"); + + if (options.get("roles_attribute") != null) + { + rolesAttribute = (String) options.get("roles_attribute"); + } + + if (options.get("groups_attribute") != null) + { + groupsAttribute = (String) options.get("groups_attribute"); + } + + // private on AbstractLoginModule + this.skipOnPreviousSuccess = BooleanUtil + .toBoolean((String) options.get(OPTION_SKIP_ON_PREVIOUS_SUCCESS), false); + } + + @Override + public boolean login() throws LoginException + { + if (skipOnPreviousSuccess && this.getSharedStatus() == STATUS_SUCCEEDED) + { + return true; + } + + if (this.callbackHandler == null) + { + throw new LoginException("Error: no CallbackHandler available"); + } + + List<Callback> callbacksList = new ArrayList<Callback>(); + + TextInputCallback ticketCallback = new TextInputCallback("ticket"); + TextInputCallback serviceCallback = null; + TextInputCallback casValidateUrlCallback = null; + RealmCallback realmCallback = null; + + callbacksList.add(ticketCallback); + + if (StringUtils.isBlank(service)) + { + // the service has not been hardcoded, so give the application + // a callback which can be used to specify it + serviceCallback = new TextInputCallback("service"); + callbacksList.add(serviceCallback); + } + + if (StringUtils.isBlank(service)) + { + // the casValidateUrl has not been hardcoded, so give the application + // a callback which can be used to specify it + casValidateUrlCallback = new TextInputCallback("casValidateUrl"); + callbacksList.add(casValidateUrlCallback); + } + + // if the realm is not defined in the jaas configuration + // we ask use a callback to get the value + if (this.useRealmCallback) + { + realmCallback = new RealmCallback(); + callbacksList.add(realmCallback); + } + + this.success = false; + + Callback[] callbacks = callbacksList.toArray(new Callback[callbacksList.size()]); + + try + { + this.callbackHandler.handle(callbacks); + + } + catch (IOException e) + { + if (log.isDebugEnabled()) + { + log.debug("Exception caught", e); + } + throw new LoginException(e.toString()); + } + catch (UnsupportedCallbackException e) + { + if (log.isDebugEnabled()) + { + log.debug(e.getMessage(), e); + } + throw new LoginException(e.getCallback().toString() + " not available"); + } + + // this.name = ((NameCallback) callbacks[0]).getName(); + // this.pswd = ((PasswordCallback) callbacks[1]).getPassword(); + if (this.useRealmCallback) + { + this.realm = StringUtils.defaultIfEmpty(realmCallback.getRealm(), this.realm); + } + + String ticket = ticketCallback.getText(); + if (StringUtils.isNotEmpty(ticket)) + { + if (serviceCallback != null) + { + service = serviceCallback.getText(); + } + + if (casValidateUrlCallback != null) + { + casValidateUrl = casValidateUrlCallback.getText(); + } + + Cas20ProxyTicketValidator pv = new Cas20ProxyTicketValidator(casValidateUrl); + + Assertion assertion; + try + { + assertion = pv.validate(ticket, service); + } + catch (TicketValidationException e) + { + throw new LoginException(e.getMessage()); + } + + if (assertion.getPrincipal() != null) + { + + principal = assertion.getPrincipal(); + subject.getPrincipals().add(principal); + + setEntity(); + + user = new CasMagnoliaUser(subject); + + this.success = true; + this.setSharedStatus(STATUS_SUCCEEDED); + } + + } + + return this.success; + } + + /** + * {@inheritDoc} + */ + @Override + public void validateUser() throws LoginException + { + + } + + @Override + public boolean commit() throws LoginException + { + if (principal != null) + { + subject.getPrincipals().add(principal); + return true; + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public User getUser() + { + return user; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean release() + { + if (principal != null) + { + principal = null; + user = null; + return true; + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public void setACL() + { + // delegate to the Authorization module + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("unchecked") + @Override + public void setEntity() + { + EntityImpl entity = new EntityImpl(); + entity.addProperty(Entity.NAME, this.principal.getName()); + + Map<String, String> attributes = this.principal.getAttributes(); + + String fullName = attributes.get("title"); + if (fullName != null) + { + entity.addProperty(Entity.FULL_NAME, fullName); + } + + entity.addProperty(Entity.LANGUAGE, "en"); + + this.subject.getPrincipals().add(entity); + + String[] roles = StringUtils.split(attributes.get(rolesAttribute)); + String[] groups = StringUtils.split(attributes.get(groupsAttribute)); + + if (roles == null) + { + roles = new String[0]; + } + if (groups == null) + { + groups = new String[0]; + } + + if (defaultGroup != null) + { + groups = (String[]) ArrayUtils.add(groups, defaultGroup); + } + + if (defaultRole != null) + { + roles = (String[]) ArrayUtils.add(roles, defaultRole); + } + + addGroups(groups); + addRoles(roles); + + } + + /** + * Set the list of groups, info.magnolia.jaas.principal.GroupList. + * @param groups array of group names + */ + protected void addGroups(String[] groups) + { + GroupList groupList = new GroupListImpl(); + + for (int j = 0; j < groups.length; j++) + { + String group = groups[j]; + groupList.add(group); + addGroupName(group); + } + + this.subject.getPrincipals().add(groupList); + } + + /** + * Set the list of roles, info.magnolia.jaas.principal.RoleList. + * @param roles array of role names + */ + protected void addRoles(String[] roles) + { + RoleList roleList = new RoleListImpl(); + + for (int j = 0; j < roles.length; j++) + { + String role = roles[j]; + roleList.add(role); + addRoleName(role); + } + + this.subject.getPrincipals().add(roleList); + } + +} \ No newline at end of file Added: trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CasClientCallback.java =================================================================== --- trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CasClientCallback.java (rev 0) +++ trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CasClientCallback.java 2008-12-03 16:06:59 UTC (rev 931) @@ -0,0 +1,216 @@ +/** + * Copyright Openmind http://www.openmindonline.it + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +package net.sourceforge.openutils.mgnlcas; + +import info.magnolia.cms.security.auth.callback.AbstractHttpClientCallback; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.jasig.cas.client.util.CommonUtils; +import org.jasig.cas.client.validation.Assertion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * Magnolia CAS Callback, based on CAS org.jasig.cas.client.authentication.AuthenticationFilter + * @author fgiust + * @version $Id: CasClientCallback.java 4896 2008-10-08 16:23:10Z manuel $ + */ +public class CasClientCallback extends AbstractHttpClientCallback +{ + + /** + * Represents the constant for where the gateway flag will be located in session. + */ + public static final String CONST_CAS_GATEWAY = "_const_cas_gateway_"; + + /** + * Represents the constant for where the assertion will be located in session. + */ + public static final String CONST_CAS_ASSERTION = "_const_cas_assertion_"; + + private Logger log = LoggerFactory.getLogger(CasClientCallback.class); + + /** + * Defines the parameter to look for for the artifact. + */ + private String artifactParameterName = "ticket"; + + /** + * Defines the parameter to look for for the service. + */ + private String serviceParameterName = "service"; + + /** + * Sets where response.encodeUrl should be called on service urls when constructed. + */ + private boolean encodeServiceUrl = true; + + /** + * The URL to the CAS Server login. + */ + private String casServerLoginUrl; + + /** + * Whether to send the renew request or not. + */ + private boolean renew; + + /** + * Whether to send the gateway request or not. + */ + private boolean gateway; + + public final void setRenew(final boolean renew) + { + this.renew = renew; + } + + public final void setGateway(final boolean gateway) + { + this.gateway = gateway; + } + + public final void setCasServerLoginUrl(final String casServerLoginUrl) + { + this.casServerLoginUrl = casServerLoginUrl; + } + + /** + * Sets the artifactParameterName. + * @param artifactParameterName the artifactParameterName to set + */ + public void setArtifactParameterName(String artifactParameterName) + { + this.artifactParameterName = artifactParameterName; + } + + /** + * Sets the serviceParameterName. + * @param serviceParameterName the serviceParameterName to set + */ + public void setServiceParameterName(String serviceParameterName) + { + this.serviceParameterName = serviceParameterName; + } + + /** + * Sets the encodeServiceUrl. + * @param encodeServiceUrl the encodeServiceUrl to set + */ + public void setEncodeServiceUrl(boolean encodeServiceUrl) + { + this.encodeServiceUrl = encodeServiceUrl; + } + + /** + * {@inheritDoc} + */ + @Override + public void doCallback(HttpServletRequest request, HttpServletResponse response) + { + + final HttpSession session = request.getSession(false); + + if (session != null) + { + // don't redirect to cas if user is already logged in + if (session.getAttribute("info.magnolia.context.UserContextImpl.user") != null) + { + try + { + request.getRequestDispatcher("/errors/401.html").forward(request, response); + } + catch (ServletException e) + { + // ignore + } + catch (IOException e) + { + // ignore + } + return; + } + } + final String ticket = request.getParameter(this.artifactParameterName); + final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null; + final boolean wasGatewayed = session != null && session.getAttribute(CONST_CAS_GATEWAY) != null; + + if (CommonUtils.isBlank(ticket) && assertion == null && !wasGatewayed) + { + + String service = RequestUtils.absoluteUrl(request); + log.debug("no ticket and no assertion found"); + if (this.gateway) + { + log.debug("setting gateway attribute in session"); + request.getSession(true).setAttribute(CONST_CAS_GATEWAY, "yes"); + } + + final String serviceUrl = CommonUtils.constructServiceUrl( + request, + response, + service, + null, + this.artifactParameterName, + this.encodeServiceUrl); + + if (log.isDebugEnabled()) + { + log.debug("Constructed service url: " + serviceUrl); + } + + String urlToRedirectTo = CommonUtils.constructRedirectUrl( + this.casServerLoginUrl, + this.serviceParameterName, + serviceUrl, + this.renew, + this.gateway); + + urlToRedirectTo = urlToRedirectTo + "&locale=" + request.getLocale().toString(); + + if (log.isDebugEnabled()) + { + log.debug("redirecting to \"" + urlToRedirectTo + "\""); + } + + try + { + response.sendRedirect(urlToRedirectTo); + } + catch (IOException e) + { + log.error(e.getMessage(), e); + } + return; + } + + if (session != null) + { + log.debug("removing gateway attribute from session"); + session.setAttribute(CONST_CAS_GATEWAY, null); + } + } + +} Added: trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CasLogin.java =================================================================== --- trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CasLogin.java (rev 0) +++ trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CasLogin.java 2008-12-03 16:06:59 UTC (rev 931) @@ -0,0 +1,242 @@ +/** + * Copyright Openmind http://www.openmindonline.it + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +package net.sourceforge.openutils.mgnlcas; + +import info.magnolia.cms.security.SecuritySupport; +import info.magnolia.cms.security.User; +import info.magnolia.cms.security.auth.callback.RealmCallback; +import info.magnolia.cms.security.auth.login.LoginHandler; +import info.magnolia.cms.security.auth.login.LoginHandlerBase; +import info.magnolia.cms.security.auth.login.LoginResult; + +import java.io.IOException; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.TextInputCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * @author fgiust + * @version $Id: CasLogin.java 4266 2008-09-25 08:18:30Z daniela $ + */ +public class CasLogin extends LoginHandlerBase implements LoginHandler +{ + + private static final Logger log = LoggerFactory.getLogger(CasLogin.class); + + /** + * Defines the parameter to look for for the artifact. + */ + private String artifactParameterName = "ticket"; + + /** + * The JAAS chain/module to use. + */ + private String jaasChain = "magnolia"; + + private String realm; + + private String casValidateUrl; + + /** + * Sets the artifactParameterName. + * @param artifactParameterName the artifactParameterName to set + */ + public void setArtifactParameterName(String artifactParameterName) + { + this.artifactParameterName = artifactParameterName; + } + + public String getJaasChain() + { + return this.jaasChain; + } + + public void setJaasChain(String jaasChain) + { + this.jaasChain = jaasChain; + } + + /** + * Returns the realm. + * @return the realm + */ + public String getRealm() + { + return realm; + } + + /** + * Sets the realm. + * @param realm the realm to set + */ + public void setRealm(String realm) + { + this.realm = realm; + } + + /** + * Returns the casValidateUrl. + * @return the casValidateUrl + */ + public String getCasValidateUrl() + { + return casValidateUrl; + } + + /** + * Sets the casValidateUrl. + * @param casValidateUrl the casValidateUrl to set + */ + public void setCasValidateUrl(String casValidateUrl) + { + this.casValidateUrl = casValidateUrl; + } + + public LoginResult handle(HttpServletRequest request, HttpServletResponse response) + { + + final String ticket = request.getParameter(this.artifactParameterName); + + if (StringUtils.isNotEmpty(ticket)) + { + String service = RequestUtils.absoluteUrl(request); + // solo se è l'ultimo carattere + if (service.lastIndexOf("/") == (service.length() - 1)) + { + service = service.substring(0, service.lastIndexOf("/")); + } + CasCallBackHandler handler = new CasCallBackHandler(service, ticket, realm); + + return authenticateCas(handler, getJaasChain()); + } + + return LoginResult.NOT_HANDLED; + } + + protected LoginResult authenticateCas(CasCallBackHandler callbackHandler, String customLoginModule) + { + Subject subject; + try + { + LoginContext loginContext = new LoginContext( + StringUtils.defaultString(customLoginModule, "magnolia"), + callbackHandler); + + loginContext.login(); + subject = loginContext.getSubject(); + User user = SecuritySupport.Factory.getInstance().getUserManager().getUser(subject); + + if (user != null) + { + user.setSubject(subject); + } + else + { + log + .error("Unable to obtain a user from userManager, maybe the external user manager is not configured for the cas realm?"); + } + + return new LoginResult(LoginResult.STATUS_SUCCEEDED, user); + } + catch (LoginException e) + { + log.info("Can't login due to:", e); + return new LoginResult(LoginResult.STATUS_FAILED, e); + } + } + + public class CasCallBackHandler implements CallbackHandler + { + + private String service; + + private String ticket; + + private String realm; + + public CasCallBackHandler(String service, String ticket, String realm) + { + this.service = service; + this.ticket = ticket; + this.realm = realm; + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + for (int i = 0; i < callbacks.length; i++) + { + if (callbacks[i] instanceof TextInputCallback) + { + TextInputCallback text = (TextInputCallback) callbacks[i]; + if ("ticket".equals(text.getPrompt())) + { + log.info(getTicket()); + text.setText(getTicket()); + } + else if ("service".equals(text.getPrompt())) + { + log.info(getService()); + text.setText(getService()); + } + else if ("casValidateUrl".equals(text.getPrompt())) + { + log.info(casValidateUrl); + text.setText(casValidateUrl); + } + } + else if (callbacks[i] instanceof RealmCallback) + { + log.info(this.realm); + ((RealmCallback) callbacks[i]).setRealm(this.realm); + } + else + { + throw (new UnsupportedCallbackException(callbacks[i], "Callback class not supported")); + } + } + } + + public String getTicket() + { + return ticket; + } + + public String getService() + { + return service; + } + + public String getRealm() + { + return realm; + } + + } +} Added: trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CasMagnoliaUser.java =================================================================== --- trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CasMagnoliaUser.java (rev 0) +++ trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/CasMagnoliaUser.java 2008-12-03 16:06:59 UTC (rev 931) @@ -0,0 +1,45 @@ +/** + * Copyright Openmind http://www.openmindonline.it + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +package net.sourceforge.openutils.mgnlcas; + +import info.magnolia.cms.security.ExternalUser; + +import javax.security.auth.Subject; + + +/** + * @author fgiust + * @version $Id: CasMagnoliaUser.java 2244 2008-08-11 19:31:53Z fgiust $ + */ +public class CasMagnoliaUser extends ExternalUser +{ + + /** + * Stable serialVersionUID. + */ + private static final long serialVersionUID = 42L; + + /** + * @param subject + */ + protected CasMagnoliaUser(Subject subject) + { + super(subject); + } + +} Added: trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/RequestUtils.java =================================================================== --- trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/RequestUtils.java (rev 0) +++ trunk/openutils-mgnlcas/src/main/java/net/sourceforge/openutils/mgnlcas/RequestUtils.java 2008-12-03 16:06:59 UTC (rev 931) @@ -0,0 +1,55 @@ +/** + * Copyright Openmind http://www.openmindonline.it + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +package net.sourceforge.openutils.mgnlcas; + +import javax.servlet.http.HttpServletRequest; + + +/** + * @author fgiust + * @version $Id: RequestUtils.java 4124 2008-09-22 14:56:46Z fgiust $ + */ +public final class RequestUtils +{ + + private RequestUtils() + { + // don't instantiate + } + + public static String absoluteUrl(HttpServletRequest request) + { + + String host = request.getServerName(); + int port = request.getServerPort(); + String scheme = request.getScheme(); + StringBuilder sb = new StringBuilder(); + sb.append(scheme); + sb.append("://"); + sb.append(host); + if (port != 0 && port != 80 && port != 443) + { + sb.append(":"); + sb.append(port); + } + sb.append(request.getRequestURI()); + + return sb.toString(); + + } +} Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2008-12-03 15:14:24 UTC (rev 930) +++ trunk/pom.xml 2008-12-03 16:06:59 UTC (rev 931) @@ -242,6 +242,7 @@ <module>openutils-mgnlcontrols</module> <module>openutils-spring-rmibernate</module> <module>openutils-mgnlmessages</module> + <module>openutils-mgnlcas</module> <!-- <module>openutils-elfunctions</module> <module>openutils-mgnlmessages</module> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |