You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lenya.apache.org by an...@apache.org on 2008/04/03 19:02:38 UTC
svn commit: r644407 - in /lenya/branches/branch_1_2_x_shibboleth/src:
java/org/apache/lenya/ac/shibboleth/ webapp/lenya/resources/i18n/
Author: andreas
Date: Thu Apr 3 10:02:35 2008
New Revision: 644407
URL: http://svn.apache.org/viewvc?rev=644407&view=rev
Log:
Don't redirect a Shibboleth user twice to the WAYF server. This should avoid the redirect loop (SP->WAYF->IdP->SP) when authorization fails.
Added:
lenya/branches/branch_1_2_x_shibboleth/src/java/org/apache/lenya/ac/shibboleth/ShibbolethUserReference.java
Modified:
lenya/branches/branch_1_2_x_shibboleth/src/java/org/apache/lenya/ac/shibboleth/ShibbolethAuthenticator.java
lenya/branches/branch_1_2_x_shibboleth/src/webapp/lenya/resources/i18n/cmsui.xml
lenya/branches/branch_1_2_x_shibboleth/src/webapp/lenya/resources/i18n/cmsui_de.xml
Modified: lenya/branches/branch_1_2_x_shibboleth/src/java/org/apache/lenya/ac/shibboleth/ShibbolethAuthenticator.java
URL: http://svn.apache.org/viewvc/lenya/branches/branch_1_2_x_shibboleth/src/java/org/apache/lenya/ac/shibboleth/ShibbolethAuthenticator.java?rev=644407&r1=644406&r2=644407&view=diff
==============================================================================
--- lenya/branches/branch_1_2_x_shibboleth/src/java/org/apache/lenya/ac/shibboleth/ShibbolethAuthenticator.java (original)
+++ lenya/branches/branch_1_2_x_shibboleth/src/java/org/apache/lenya/ac/shibboleth/ShibbolethAuthenticator.java Thu Apr 3 10:02:35 2008
@@ -33,6 +33,7 @@
import org.apache.cocoon.environment.Context;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.Session;
import org.apache.cocoon.environment.http.HttpEnvironment;
import org.apache.lenya.ac.AccessControlException;
import org.apache.lenya.ac.AccessControllerResolver;
@@ -41,16 +42,17 @@
import org.apache.lenya.ac.ErrorHandler;
import org.apache.lenya.ac.Group;
import org.apache.lenya.ac.Identity;
+import org.apache.lenya.ac.Message;
import org.apache.lenya.ac.Policy;
import org.apache.lenya.ac.Role;
import org.apache.lenya.ac.UserManager;
import org.apache.lenya.ac.UserReference;
import org.apache.lenya.ac.impl.DefaultAccessController;
import org.apache.lenya.ac.impl.TransientUser;
-import org.apache.lenya.ac.impl.TransientUserReference;
import org.apache.lenya.ac.impl.UserAuthenticator;
import org.apache.lenya.ac.saml.AttributeTranslator;
import org.apache.lenya.ac.saml.UserFieldsMapper;
+import org.apache.lenya.cms.cocoon.acting.DelegatingAuthorizerAction;
import org.apache.lenya.cms.cocoon.components.context.ContextUtility;
import org.apache.lenya.cms.publication.Proxy;
import org.apache.lenya.cms.publication.Publication;
@@ -62,7 +64,6 @@
import org.apache.shibboleth.impl.AssertionConsumerServiceImpl;
import org.opensaml.SAMLBrowserProfile.BrowserProfileResponse;
-
/**
* <p>
* Shibboleth-based authenticator.
@@ -71,17 +72,21 @@
* Configuration:
* </p>
* <ul>
- * <li> <code><redirect-to-wayf>true|false</redirect-to-wayf></code> - if the
- * application should redirect to the WAYF server instead of the login screen if a resource is
- * protected only via group rules </li>
+ * <li> <code><redirect-to-wayf>true|false</redirect-to-wayf></code> -
+ * if the application should redirect to the WAYF server instead of the login
+ * screen if a resource is protected only via group rules </li>
*
* </pre>
*/
public class ShibbolethAuthenticator extends UserAuthenticator implements Configurable {
+ protected static final String PREVIOUSLY_REDIRECTED_USER = ShibbolethAuthenticator.class
+ .getName()
+ + "previouslyRedirectedUser";
+
/**
- * Configuration option to determine if the WAYF server should be used for logging in to
- * rule-only protected pages.
+ * Configuration option to determine if the WAYF server should be used for
+ * logging in to rule-only protected pages.
*/
protected static final String REDIRECT_TO_WAYF = "redirect-to-wayf";
@@ -93,11 +98,13 @@
private boolean redirectToWayf = false;
/**
- * Authenticates the request. If the request contains the parameters <em>username</em> and
- * <em>password</em>, the authentication is delegated to the super class
- * {@link UserAuthenticator}. Otherwise, the Shibboleth browser profile request is evaluated.
+ * Authenticates the request. If the request contains the parameters
+ * <em>username</em> and <em>password</em>, the authentication is
+ * delegated to the super class {@link UserAuthenticator}. Otherwise, the
+ * Shibboleth browser profile request is evaluated.
* @see org.apache.lenya.ac.impl.UserAuthenticator#authenticate(org.apache.lenya.ac.AccreditableManager,
- * org.apache.cocoon.environment.Request, org.apache.lenya.ac.ErrorHandler)
+ * org.apache.cocoon.environment.Request,
+ * org.apache.lenya.ac.ErrorHandler)
*/
public boolean authenticate(AccreditableManager accreditableManager, Request request,
ErrorHandler handler) throws AccessControlException {
@@ -193,16 +200,17 @@
}
identity.removeIdentifiable(oldUser);
}
- identity.addIdentifiable(new TransientUserReference(user));
+ identity.addIdentifiable(new ShibbolethUserReference(user));
if (getLogger().isDebugEnabled()) {
getLogger().debug("Adding user [" + user + "] to identity.");
}
}
/**
- * Passes the attributes from the <em>samlAttributes</em> parameter to the <em>user</em>
- * object. The {@link AttributeTranslator}�service is used to translate the attributes. The
- * name and e-mail attributes are extracted using the {@link UserFieldsMapper}.
+ * Passes the attributes from the <em>samlAttributes</em> parameter to the
+ * <em>user</em> object. The {@link AttributeTranslator}�service is
+ * used to translate the attributes. The name and e-mail attributes are
+ * extracted using the {@link UserFieldsMapper}.
* @param user
* @param samlAttributes
* @throws AccessControlException
@@ -243,7 +251,8 @@
}
/**
- * Extracts the <code>HttpServletRequest</code> object from the current Cocoon context.
+ * Extracts the <code>HttpServletRequest</code> object from the current
+ * Cocoon context.
* @return An <code>HttpServletRequest</code> object.
* @throws AccessControlException
*/
@@ -269,47 +278,110 @@
* This method returns the URI which displays the login screen:
* </p>
* <ul>
- * <li>If the configuration option {@link #REDIRECT_TO_WAYF}�is set to <code>true</code> and
- * the request points to a page which is only protected by rules, we assume that the Shibboleth
- * authentication shall be used and return the URL which redirects to the WAYF server.</li>
+ * <li>If the configuration option {@link #REDIRECT_TO_WAYF} is set to
+ * <code>true</code> and the request points to a page which is only
+ * protected by rules, we assume that the Shibboleth authentication shall be
+ * used and return the URL which redirects to the WAYF server.</li>
* <li>Otherwise, the Lenya login usecase URL is returned.</li>
* </ul>
* @return A string.
* @see org.apache.lenya.ac.impl.UserAuthenticator#getLoginUri(org.apache.cocoon.environment.Request)
*/
- public String getLoginUri(Request request) {
+ public String getLoginUri(Request request) {
+ String loginUri = null;
+
if (this.redirectToWayf && isOnlyRuleProtected(request)) {
- ContextUtility contextUtil = null;
- String proxyUrl;
- try {
- contextUtil = (ContextUtility) this.manager.lookup(ContextUtility.ROLE);
- Context context = ObjectModelHelper.getContext(contextUtil.getObjectModel());
- String servletContextPath = context.getRealPath("");
- String webappUrl = ServletHelper.getWebappURI(request);
- URLInformation info = new URLInformation(webappUrl);
- String pubId = info.getPublicationId();
- Publication pub = PublicationFactory.getPublication(pubId, servletContextPath);
-
- String area = info.getArea();
- Proxy proxy = pub.getProxy(area, true);
- if (proxy != null) {
- String prefix = "/" + pubId + "/" + area;
- String areaUrl = webappUrl.substring(prefix.length());
- proxyUrl = proxy.getUrl() + areaUrl;
- } else {
- proxyUrl = request.getContextPath() + webappUrl;
+
+ // avoid redirect loop (WAYF->IdP->SP->WAYF) because of failing authorization
+ ShibbolethUserReference user = getLoggedInShibboletUser(request);
+ if (user != null) {
+ String userId = user.getId();
+ String previouslyRedirectedUserId = getPreviouslyRedirectedUser(request);
+ if (previouslyRedirectedUserId != null && userId.equals(previouslyRedirectedUserId)) {
+ // reportAuthorizationError(request);
+ loginUri = super.getLoginUri(request);
}
- } catch (Exception e) {
- throw new RuntimeException(e);
- } finally {
- if (contextUtil != null) {
- this.manager.release(contextUtil);
+ else {
+ setPreviouslyRedirectedUser(request, userId);
}
}
- return proxyUrl + "?lenya.usecase=shibboleth&lenya.step=wayf";
+ if (loginUri == null) {
+ loginUri = getWayfLoginUrl(request);
+ }
} else {
- return super.getLoginUri(request);
+ loginUri = super.getLoginUri(request);
+ }
+
+ return loginUri;
+ }
+
+ protected void reportAuthorizationError(Request request) {
+ Message msg = new Message("access-denied");
+ Message[] messages = { msg };
+ request.getSession().setAttribute(DelegatingAuthorizerAction.ERRORS, messages);
+ }
+
+ protected void setPreviouslyRedirectedUser(Request request, String userId) {
+ request.getSession().setAttribute(PREVIOUSLY_REDIRECTED_USER, userId);
+ }
+
+ protected String getPreviouslyRedirectedUser(Request request) {
+ return (String) request.getSession()
+ .getAttribute(PREVIOUSLY_REDIRECTED_USER);
+ }
+
+ /**
+ * @param request The current request.
+ * @return A Shibboleth user reference or <code>null</code> if no
+ * Shiboleth user is logged in.
+ */
+ protected ShibbolethUserReference getLoggedInShibboletUser(Request request) {
+ Session session = request.getSession(false);
+ if (session != null) {
+ Identity identity = (Identity) session.getAttribute(Identity.class.getName());
+ if (identity != null) {
+ UserReference user = identity.getUserReference();
+ if (user instanceof ShibbolethUserReference) {
+ return (ShibbolethUserReference) user;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param request The current request.
+ * @return The URI which issues a redirect to the WAYF server.
+ */
+ protected String getWayfLoginUrl(Request request) {
+ ContextUtility contextUtil = null;
+ String proxyUrl;
+ try {
+ contextUtil = (ContextUtility) this.manager.lookup(ContextUtility.ROLE);
+ Context context = ObjectModelHelper.getContext(contextUtil.getObjectModel());
+ String servletContextPath = context.getRealPath("");
+ String webappUrl = ServletHelper.getWebappURI(request);
+ URLInformation info = new URLInformation(webappUrl);
+ String pubId = info.getPublicationId();
+ Publication pub = PublicationFactory.getPublication(pubId, servletContextPath);
+
+ String area = info.getArea();
+ Proxy proxy = pub.getProxy(area, true);
+ if (proxy != null) {
+ String prefix = "/" + pubId + "/" + area;
+ String areaUrl = webappUrl.substring(prefix.length());
+ proxyUrl = proxy.getUrl() + areaUrl;
+ } else {
+ proxyUrl = request.getContextPath() + webappUrl;
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ if (contextUtil != null) {
+ this.manager.release(contextUtil);
+ }
}
+ return proxyUrl + "?lenya.usecase=shibboleth&lenya.step=wayf";
}
/**
@@ -317,9 +389,10 @@
* Checks if a page is protected only with rules:
* </p>
* <ul>
- * <li> If the aggregated policy for the current page contains credentials which assign a role
- * to a particular user or IP range, or to a group which contains explicitly assigned members,
- * the method returns <code>false</code>. </li>
+ * <li> If the aggregated policy for the current page contains credentials
+ * which assign a role to a particular user or IP range, or to a group which
+ * contains explicitly assigned members, the method returns
+ * <code>false</code>. </li>
* <li> Otherwise, the method returns <code>true</code>.
* </ul>
* @param request The request referring to the page.
@@ -390,10 +463,11 @@
/**
* <p>
- * This method returns the URL of the protected page, as passed from the identity provider as
- * the value of the {@link AssertionConsumerServiceImpl#REQ_PARAM_TARGET} request parameter. If
- * the request parameter is missing, the current URL, i.e. the assertion consumer URL, is
- * returned.
+ * This method returns the URL of the protected page, as passed from the
+ * identity provider as the value of the
+ * {@link AssertionConsumerServiceImpl#REQ_PARAM_TARGET} request parameter.
+ * If the request parameter is missing, the current URL, i.e. the assertion
+ * consumer URL, is returned.
* </p>
* @see org.apache.lenya.ac.impl.UserAuthenticator#getTargetUri(org.apache.cocoon.environment.Request)
*/
Added: lenya/branches/branch_1_2_x_shibboleth/src/java/org/apache/lenya/ac/shibboleth/ShibbolethUserReference.java
URL: http://svn.apache.org/viewvc/lenya/branches/branch_1_2_x_shibboleth/src/java/org/apache/lenya/ac/shibboleth/ShibbolethUserReference.java?rev=644407&view=auto
==============================================================================
--- lenya/branches/branch_1_2_x_shibboleth/src/java/org/apache/lenya/ac/shibboleth/ShibbolethUserReference.java (added)
+++ lenya/branches/branch_1_2_x_shibboleth/src/java/org/apache/lenya/ac/shibboleth/ShibbolethUserReference.java Thu Apr 3 10:02:35 2008
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.lenya.ac.shibboleth;
+
+import org.apache.lenya.ac.impl.TransientUser;
+import org.apache.lenya.ac.impl.TransientUserReference;
+
+/**
+ * Marker class for Shibboleth user references. Used to determine if the
+ * currently logged-in user is a Shibboleth user.
+ */
+public class ShibbolethUserReference extends TransientUserReference {
+
+ /**
+ * @param user The user.
+ */
+ public ShibbolethUserReference(TransientUser user) {
+ super(user);
+ }
+
+ private static final long serialVersionUID = 1L;
+
+}
Modified: lenya/branches/branch_1_2_x_shibboleth/src/webapp/lenya/resources/i18n/cmsui.xml
URL: http://svn.apache.org/viewvc/lenya/branches/branch_1_2_x_shibboleth/src/webapp/lenya/resources/i18n/cmsui.xml?rev=644407&r1=644406&r2=644407&view=diff
==============================================================================
--- lenya/branches/branch_1_2_x_shibboleth/src/webapp/lenya/resources/i18n/cmsui.xml (original)
+++ lenya/branches/branch_1_2_x_shibboleth/src/webapp/lenya/resources/i18n/cmsui.xml Thu Apr 3 10:02:35 2008
@@ -105,12 +105,13 @@
<message key="Authentication failed">Authentication failed</message>
<message key="try-user-lenya">Try user {0} and password {1} (editor), or user {2} and password {3} (reviewer)</message>
<message key="page-can-only-accessed-by">This page can only be accessed by</message>
+ <message key="access-denied">Access denied</message>
<!-- logout screen -->
<message key="logout-from-pub">LOGOUT from the {0} Publication</message>
<message key="Your History">Your History</message>
<message key="Login to Authoring Area">Login to Authoring Area</message>
-
+
<!-- reject screen -->
<message key="Reject">Reject</message>
<message key="reject-doc?">Do you want to reject the document {0}?</message>
Modified: lenya/branches/branch_1_2_x_shibboleth/src/webapp/lenya/resources/i18n/cmsui_de.xml
URL: http://svn.apache.org/viewvc/lenya/branches/branch_1_2_x_shibboleth/src/webapp/lenya/resources/i18n/cmsui_de.xml?rev=644407&r1=644406&r2=644407&view=diff
==============================================================================
--- lenya/branches/branch_1_2_x_shibboleth/src/webapp/lenya/resources/i18n/cmsui_de.xml (original)
+++ lenya/branches/branch_1_2_x_shibboleth/src/webapp/lenya/resources/i18n/cmsui_de.xml Thu Apr 3 10:02:35 2008
@@ -105,6 +105,7 @@
<message key="Authentication failed">Anmeldung ist fehlgeschlagen</message>
<message key="try-user-lenya">Versuchen Sie Benutzername {0} und Passwort {1} (Bearbeiter), oder Benutzername {2} und Passwort {3} (Prüfer)</message>
<message key="page-can-only-accessed-by">Auf diese Seite haben nur die folgenden Nutzer Zugriff:</message>
+ <message key="access-denied">Zugriff verweigert</message>
<!-- logout screen -->
<message key="logout-from-pub">Abmelden von der {0} Publikation</message>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@lenya.apache.org
For additional commands, e-mail: commits-help@lenya.apache.org
Re: svn commit: r644407 - in /lenya/branches/branch_1_2_x_shibboleth/src:
java/org/apache/lenya/ac/shibboleth/ webapp/lenya/resources/i18n/
Posted by Jann Forrer <ja...@id.uzh.ch>.
Andreas Hartmann wrote:
> Jann Forrer schrieb:
>> Hi Andreas
>>
>> [ ... ]
>>> @@ -193,16 +200,17 @@
>>> }
>>> identity.removeIdentifiable(oldUser);
>>> }
>>> - identity.addIdentifiable(new TransientUserReference(user));
>>> + identity.addIdentifiable(new ShibbolethUserReference(user));
>>> if (getLogger().isDebugEnabled()) {
>>> getLogger().debug("Adding user [" + user + "] to
>>> identity.");
>>> }
>>> }
>>>
>> Do you think it make sense to pass the type of UserReference
>> (TransientUserReference, ShibbolsethUserRefernce, ....) as a parameter
>> to the updateIdentity method?
>> The reason is ask is: I extended the ShibbolethAuthenticator class
>> adding a authenticateLdapUser method in order to authenticate ldap user
>> which are not defnied in the cms. Within this method I also use the
>> updateidenty method of the super class.
>
> If you need this functionality, IMO it would make sense to introduce a
> cascade of authenticators. The Java class hierarchy is not flexible
> enough to handle such cases.
>
> DefaultAccessController:
>
> public boolean authenticate(Request request, ErrorHandler handler)
> throws AccessControlException {
>
> assert request != null;
> boolean authenticated = false;
> Authenticators[] authenticators = getAuthenticators();
> int i = 0;
> while (!authenticated) {
> authenticated = authenticators[i].authenticate(
> getAccreditableManager(), request, handler);
> i++;
> }
> return authenticated;
> }
>
> Would this meet your requirements?
>
I think yes. But does it make sense to have inheritance within the
authenticators like:
AbstractTransientUserAuthenticator
¦ ¦
¦ ¦
ShibbolethAuthenticator LdapAuthenticator
because Authenticators for Transient-User have a lot in common.
and there could be something similar for User defined in the system like:
AbstractFileAuthenticator
¦ ¦
¦ ¦
SomeFileAuthenticator SomeOtherFileAuthenticator
>
>> However In the ldap case i don't need to add a ShibbolethUserReference
>> but a TransientUserReference to the identity.
>
> In this case I'd rather introduce the method
>
> ShibbolethAuthenticator.createReference(User user);
>
>
Ok, I will try it. Thanks for the pointers.
Jann
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lenya.apache.org
For additional commands, e-mail: dev-help@lenya.apache.org
Re: svn commit: r644407 - in /lenya/branches/branch_1_2_x_shibboleth/src:
java/org/apache/lenya/ac/shibboleth/ webapp/lenya/resources/i18n/
Posted by Andreas Hartmann <an...@apache.org>.
Jann Forrer schrieb:
> Hi Andreas
>
> [ ... ]
>> @@ -193,16 +200,17 @@
>> }
>> identity.removeIdentifiable(oldUser);
>> }
>> - identity.addIdentifiable(new TransientUserReference(user));
>> + identity.addIdentifiable(new ShibbolethUserReference(user));
>> if (getLogger().isDebugEnabled()) {
>> getLogger().debug("Adding user [" + user + "] to identity.");
>> }
>> }
>>
> Do you think it make sense to pass the type of UserReference
> (TransientUserReference, ShibbolsethUserRefernce, ....) as a parameter
> to the updateIdentity method?
> The reason is ask is: I extended the ShibbolethAuthenticator class
> adding a authenticateLdapUser method in order to authenticate ldap user
> which are not defnied in the cms. Within this method I also use the
> updateidenty method of the super class.
If you need this functionality, IMO it would make sense to introduce a
cascade of authenticators. The Java class hierarchy is not flexible
enough to handle such cases.
DefaultAccessController:
public boolean authenticate(Request request, ErrorHandler handler)
throws AccessControlException {
assert request != null;
boolean authenticated = false;
Authenticators[] authenticators = getAuthenticators();
int i = 0;
while (!authenticated) {
authenticated = authenticators[i].authenticate(
getAccreditableManager(), request, handler);
i++;
}
return authenticated;
}
Would this meet your requirements?
> However In the ldap case i don't need to add a ShibbolethUserReference
> but a TransientUserReference to the identity.
In this case I'd rather introduce the method
ShibbolethAuthenticator.createReference(User user);
-- Andreas
--
Andreas Hartmann, CTO
BeCompany GmbH
http://www.becompany.ch
Tel.: +41 (0) 43 818 57 01
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lenya.apache.org
For additional commands, e-mail: dev-help@lenya.apache.org
Re: svn commit: r644407 - in /lenya/branches/branch_1_2_x_shibboleth/src:
java/org/apache/lenya/ac/shibboleth/ webapp/lenya/resources/i18n/
Posted by Jann Forrer <ja...@id.uzh.ch>.
Hi Andreas
[ ... ]
> @@ -193,16 +200,17 @@
> }
> identity.removeIdentifiable(oldUser);
> }
> - identity.addIdentifiable(new TransientUserReference(user));
> + identity.addIdentifiable(new ShibbolethUserReference(user));
> if (getLogger().isDebugEnabled()) {
> getLogger().debug("Adding user [" + user + "] to identity.");
> }
> }
>
Do you think it make sense to pass the type of UserReference
(TransientUserReference, ShibbolsethUserRefernce, ....) as a parameter
to the updateIdentity method?
The reason is ask is: I extended the ShibbolethAuthenticator class
adding a authenticateLdapUser method in order to authenticate ldap user
which are not defnied in the cms. Within this method I also use the
updateidenty method of the super class.
However In the ldap case i don't need to add a ShibbolethUserReference
but a TransientUserReference to the identity.
Jann
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lenya.apache.org
For additional commands, e-mail: dev-help@lenya.apache.org