Skip to content

Commit

Permalink
frontend: add support for user 'anonymous'
Browse files Browse the repository at this point in the history
Motivation:

To avoid browsers prompting users directly for credentials when an
anonymous ajax request requires authentication, the JavaScript must
always supply a username with requests.  Yet we still want to support
anonymous access.

Modification:

Update frontend so that it accepts requests with username 'anonymous'
if anonymous access is enabled; all other username+password requests
are authenticated as before.  If anonymous access is disabled then all
requests are processed as before.

Result:

Javascript can submit AJAX requests with username 'anonymous' to
achieve desired anonymous interaction without the browser prompting the
user for credentials if it turns out authentication is required.

Target: master
Patch: https://rb.dcache.org/r/9423
Acked-by: Gerd Behrmann
Request: 2.16
Require-notes: yes
Require-book: no
  • Loading branch information
paulmillar committed Jun 16, 2016
1 parent a8d9592 commit 942cca1
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 6 deletions.
@@ -0,0 +1,94 @@
package org.dcache.webdav;

import org.springframework.beans.factory.annotation.Required;

import javax.security.auth.Subject;

import java.security.Principal;
import java.util.Set;

import diskCacheV111.util.CacheException;

import org.dcache.auth.LoginNamePrincipal;
import org.dcache.auth.LoginReply;
import org.dcache.auth.LoginStrategy;
import org.dcache.auth.PasswordCredential;
import org.dcache.auth.Subjects;
import org.dcache.auth.UnionLoginStrategy.AccessLevel;
import org.dcache.auth.attributes.LoginAttribute;
import org.dcache.auth.attributes.Restrictions;

import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;
import static java.util.Objects.requireNonNull;
import static org.dcache.auth.UnionLoginStrategy.AccessLevel.READONLY;
import static org.dcache.auth.UnionLoginStrategy.AccessLevel.NONE;

/**
* Add support for logging in a particular user as Users.NOBODY, all other
* requests are passed on to some wrapped LoginStrategy. If AccessLevel is NONE
* then all requests are passed onto the wrapped LoginStrategy.
*/
public class AnonymousUserLoginStrategy implements LoginStrategy
{
private LoginStrategy _inner;
private String _username;
private AccessLevel _anonymousAccess = NONE;

public void setAnonymousAccess(AccessLevel level)
{
_anonymousAccess = requireNonNull(level);
}

public AccessLevel getAnonymousAccess()
{
return _anonymousAccess;
}

@Required
public void setNonAnonymousStrategy(LoginStrategy strategy)
{
_inner = requireNonNull(strategy);
}

@Required
public void setUsername(String username)
{
_username = requireNonNull(username);
}

private boolean isAnonymousUser(Subject subject)
{
return subject.getPrivateCredentials().stream()
.filter(PasswordCredential.class::isInstance)
.map(PasswordCredential.class::cast)
.anyMatch(p -> _username.equals(p.getUsername())) ||
subject.getPrincipals().stream()
.filter(LoginNamePrincipal.class::isInstance)
.anyMatch(p -> _username.equals(p.getName()));
}

@Override
public LoginReply login(Subject subject) throws CacheException
{
if (_anonymousAccess != NONE && isAnonymousUser(subject)) {
Set<LoginAttribute> attributes = _anonymousAccess == READONLY ?
singleton(Restrictions.readOnly()) : emptySet();
return new LoginReply(Subjects.NOBODY, attributes);
}

return _inner.login(subject);
}

@Override
public Principal map(Principal principal) throws CacheException
{
return _inner.map(principal);
}

@Override
public Set<Principal> reverseMap(Principal principal) throws CacheException
{
return _inner.reverseMap(principal);
}
}
Expand Up @@ -72,22 +72,20 @@
</constructor-arg>
</bean>

<bean id="union-login-strategy" class="org.dcache.auth.UnionLoginStrategy">
<bean id="login-strategy" class="org.dcache.webdav.AnonymousUserLoginStrategy">
<description>Processes login requests</description>
<property name="loginStrategies">
<list>
<property name="nonAnonymousStrategy">
<bean class="org.dcache.services.login.RemoteLoginStrategy">
<property name="cellStub" ref="login-stub"/>
</bean>
</list>
</property>
<property name="fallbackToAnonymous" value="false"/>
<property name="anonymousAccess" value="${frontend.authz.anonymous-operations}"/>
<property name="username" value="anonymous"/>
</bean>

<bean id="cache-login-strategy" class="org.dcache.auth.CachingLoginStrategy">
<description>Processes mapping requests</description>
<constructor-arg index="0" ref="union-login-strategy" />
<constructor-arg index="0" ref="login-strategy" />
<constructor-arg index="1" value="${frontend.service.gplazma.cache.size}" />
<constructor-arg index="2" value="${frontend.service.gplazma.cache.timeout}" />
<constructor-arg index="3" value="${frontend.service.gplazma.cache.timeout.unit}" />
Expand Down

0 comments on commit 942cca1

Please sign in to comment.