/* dCache - http://www.dcache.org/
*
* Copyright (C) 2013 Deutsches Elektronen-Synchrotron
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package diskCacheV111.srm.dcache;
import org.globus.gsi.gssapi.jaas.GlobusPrincipal;
import javax.annotation.Nonnull;
import javax.security.auth.Subject;
import diskCacheV111.util.FsPath;
import org.dcache.auth.LoginReply;
import org.dcache.auth.Subjects;
import org.dcache.auth.attributes.Restriction;
import org.dcache.auth.attributes.Restrictions;
import org.dcache.auth.attributes.RootDirectory;
import org.dcache.srm.SRMUser;
import org.dcache.srm.request.Request;
import org.dcache.util.NetLoggerBuilder;
import static com.google.common.base.Preconditions.checkNotNull;
import static diskCacheV111.srm.dcache.CanonicalizingByteArrayStore.Token;
import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;
/**
* SRMUser adaptor for Subjects.
*
* Some authorization strategies will establish a new login session when loading
* the user identity back from the SRM database. Since this login may fail, a
* DcacheUser may represent a user that isn't logged into dCache. This will only
* ever be the case for request owners loaded back from the database.
*
* The wrapper maintains a token referencing the user in the SRM database. As long
* as this Token is referenced, the user is not eligible for garbage collection.
*/
public class DcacheUser implements SRMUser
{
private final Token token;
private final Subject subject;
private final FsPath root;
private final boolean isLoggedIn;
private final Restriction restriction;
public DcacheUser(Token token, LoginReply login)
{
this.isLoggedIn = true;
this.token = token;
this.subject = checkNotNull(login.getSubject());
this.restriction = login.getRestriction();
this.root =
login.getLoginAttributes().stream()
.filter(RootDirectory.class::isInstance)
.findFirst()
.map(RootDirectory.class::cast)
.map(RootDirectory::getRoot)
.map(FsPath::create)
.orElse(FsPath.ROOT);
}
public DcacheUser(Token token, GlobusPrincipal dn)
{
this.token = token;
this.subject = new Subject(true, singleton(dn), emptySet(), emptySet());
this.root = FsPath.ROOT;
this.isLoggedIn = false;
this.restriction = Restrictions.denyAll();
}
public DcacheUser()
{
this.token = null;
this.subject = Subjects.NOBODY;
this.root = FsPath.ROOT;
this.isLoggedIn = false;
this.restriction = Restrictions.denyAll();
}
boolean isLoggedIn()
{
return isLoggedIn;
}
@Override
public int getPriority()
{
return 0;
}
@Override
public Long getId()
{
return (token == null) ? null : token.getId();
}
@Nonnull
public Subject getSubject()
{
return subject;
}
@Nonnull
public FsPath getRoot()
{
return root;
}
@Override
public String toString()
{
return subject.getPrincipals() + " " + root;
}
public Restriction getRestriction()
{
return restriction;
}
@Override
public String getDisplayName()
{
return Subjects.getDisplayName(subject);
}
@Override
public boolean hasAccessTo(Request request)
{
DcacheUser user = (DcacheUser) request.getUser();
if (!isLoggedIn() || !user.isLoggedIn()) {
return false;
}
Subject owner = user.getSubject();
return Subjects.hasUid(subject, Subjects.getUid(owner)) ||
Subjects.hasGid(subject, Subjects.getPrimaryGid(owner));
}
@Override
public CharSequence getDescriptiveName()
{
return NetLoggerBuilder.describeSubject(subject);
}
}