package org.dcache.auth;
import javax.annotation.Nonnull;
import javax.security.auth.Subject;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.dcache.auth.attributes.LoginAttribute;
import org.dcache.auth.attributes.Restriction;
import org.dcache.auth.attributes.Restrictions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.filter;
/**
* Immutable encapsulation of a login result as provided by a
* LoginStrategy. The LoginReply embeds a logged in Subject with all
* mapped principals and login attributes associatated with the
* current login.
*/
public class LoginReply
{
private final Subject _subject;
private final Set<LoginAttribute> _attributes;
public LoginReply()
{
_subject = new Subject();
_attributes = new HashSet<>();
}
public LoginReply(Subject subject, Set<LoginAttribute> attributes)
{
_subject = checkNotNull(subject);
_attributes = checkNotNull(attributes);
}
/**
* Returns the Subject of this LoginReply.
*/
@Nonnull
public Subject getSubject()
{
return _subject;
}
/**
* Return the Set of login attributes associated with this
* LoginReply. Each element represents some attributes associated
* with the LoginReply.
*
* The returned Set is backed by this LoginReply's internal
* login attributes Set. Any modification to the returned Set
* affects the internal login attributes Set as well.
*/
@Nonnull
public Set<LoginAttribute> getLoginAttributes()
{
return _attributes;
}
/**
* Return a Set of login attributes associated with this LoginReply
* that are instances or subclasses of the specified Class.
*
* The returned Set is not backed by this LoginReply's internal
* login attributes Set. A new Set is created and returned for
* each method invocation. Modifications to the returned Set will
* not affect the internal login attributes Set.
*/
@Nonnull
public <T extends LoginAttribute> Set<T> getLoginAttributes(Class<T> type)
{
Set<T> result = new HashSet<>();
for (Object element: _attributes) {
if (type.isInstance(element)) {
result.add((T) element);
}
}
return result;
}
public Restriction getRestriction()
{
Iterable<Restriction> restrictions = filter(_attributes, Restriction.class);
Restriction restriction = null;
for (Restriction r : restrictions) {
if (restriction == null) {
restriction = r;
} else if (restriction.isSubsumedBy(r)) {
restriction = r;
} else if (r.isSubsumedBy(restriction)) {
// skip r, restriction is already more restrictive.
} else {
return Restrictions.concat(restrictions);
}
}
return restriction == null ? Restrictions.none() : restriction;
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LoginReply that = (LoginReply) o;
return _attributes.equals(that._attributes) && _subject.equals(that._subject);
}
@Override
public int hashCode()
{
int result = _subject.hashCode();
result = 31 * result + _attributes.hashCode();
return result;
}
@Override
public String toString()
{
String name = Subjects.getDisplayName(_subject);
if (Subjects.isNobody(_subject)) {
return "Login[" + name + "," + _attributes + "]";
} else {
return "Login[" + name + ","
+ Subjects.getUid(_subject) + ":"
+ Arrays.toString(Subjects.getGids(_subject)) + ","
+ _attributes + "]";
}
}
}