package org.dcache.auth;
import org.globus.gsi.gssapi.jaas.GlobusPrincipal;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosPrincipal;
import java.io.File;
import java.io.IOException;
import java.security.Principal;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import diskCacheV111.util.CacheException;
import diskCacheV111.util.PermissionDeniedCacheException;
import org.dcache.auth.attributes.HomeDirectory;
import org.dcache.auth.attributes.LoginAttribute;
import org.dcache.auth.attributes.Restrictions;
import org.dcache.auth.attributes.RootDirectory;
/**
* A LoginStrategy that wraps KAuthFile.
*
* Supports login for Subjects with
*
* - KeberosPrincipal and optional LoginNamePrincipal
* - GlobusPrincipal and optional LoginNamePrincipal
* - PasswordCredential
*/
public class KauthFileLoginStrategy implements LoginStrategy
{
private final File _file;
public KauthFileLoginStrategy(File file)
{
if (!file.canRead()) {
throw new IllegalArgumentException("File not found: " + file);
}
_file = file;
}
@Override
public LoginReply login(Subject subject) throws CacheException
{
String user = Subjects.getLoginName(subject);
for (KerberosPrincipal principal: subject.getPrincipals(KerberosPrincipal.class)) {
return loginByUserNameAndId(user, principal.getName());
}
for (GlobusPrincipal principal: subject.getPrincipals(GlobusPrincipal.class)) {
return loginByUserNameAndId(user, principal.getName());
}
return loginWithPassword(subject);
}
private KAuthFile loadKauthFile()
throws CacheException
{
try {
return new KAuthFile(_file.getPath());
} catch (IOException e) {
throw new PermissionDeniedCacheException("Password file not found");
}
}
private LoginReply loginByUserNameAndId(String user, String id)
throws CacheException
{
KAuthFile kauth = loadKauthFile();
if (user == null) {
user = kauth.getIdMapping(id);
if (user == null) {
throw new PermissionDeniedCacheException("Access denied");
}
}
UserAuthRecord record = kauth.getUserRecord(user);
if (record == null || !record.hasSecureIdentity(id)) {
throw new PermissionDeniedCacheException("Access denied");
}
Subject subject;
if (record.isAnonymous()) {
subject = Subjects.NOBODY;
} else {
subject = Subjects.getSubject(record);
}
return new LoginReply(subject, toLoginAttributes(record));
}
private LoginReply loginWithPassword(Subject subject)
throws CacheException
{
KAuthFile kauth = loadKauthFile();
for (PasswordCredential password: subject.getPrivateCredentials(PasswordCredential.class)) {
UserPwdRecord record =
kauth.getUserPwdRecord(password.getUsername());
if (record == null || record.isDisabled()) {
throw new PermissionDeniedCacheException("Access denied");
}
if (!record.isAnonymous() &&
!record.passwordIsValid(password.getPassword())) {
throw new PermissionDeniedCacheException("Access denied");
}
if (record.isAnonymous()) {
subject = Subjects.NOBODY;
} else {
subject = Subjects.getSubject(record, true);
}
return new LoginReply(subject, toLoginAttributes(record));
}
throw new IllegalArgumentException("Subject is not supported by KAuthFileLoginStrategy");
}
private Set<LoginAttribute> toLoginAttributes(UserAuthBase record)
{
Set<LoginAttribute> attributes = new HashSet<>();
attributes.add(new HomeDirectory(record.Home));
attributes.add(new RootDirectory(record.Root));
if (record.ReadOnly) {
attributes.add(Restrictions.readOnly());
}
return attributes;
}
@Override
public Principal map(Principal principal) throws CacheException
{
return null;
}
@Override
public Set<Principal> reverseMap(Principal principal) throws CacheException
{
return Collections.emptySet();
}
}