Commit f0dabadf authored by Tigran Mkrtchyan's avatar Tigran Mkrtchyan
Browse files

nfsv4: add login service for gss based requests

added simple implementation based on nss configuration.
parent 187f51a9
......@@ -2,6 +2,9 @@
#
#
# nfs4 domain
nfs.domain=desy.afs
# default TCP port number for Metadata Server
mds.port=2049
......
......@@ -275,6 +275,11 @@
<artifactId>dcache-auth</artifactId>
<version>0.0.10-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.sun.jna</groupId>
<artifactId>jna</artifactId>
<version>3.0.9</version>
</dependency>
</dependencies>
<!--
......
/*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program (see the file COPYING.LIB for more
* details); if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.dcache.chimera.nfs.v4;
import java.security.Principal;
import javax.security.auth.Subject;
public interface NfsLoginService {
Subject login(Principal principal);
}
/*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program (see the file COPYING.LIB for more
* details); if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.dcache.chimera.nfs.v4;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.ptr.IntByReference;
import java.security.Principal;
import javax.security.auth.Subject;
import org.dcache.auth.Subjects;
/**
*
* @author tigran
*/
public class NssIdmapper implements NfsIdMapping, NfsLoginService {
private final String _domain;
private final int NOBODY_UID = -1;
private final int NOBODY_GID = -1;
private final String NOBODY_USER = "nobody";
private final String NOBODY_GROUP = "nobody";
public NssIdmapper(String domain) {
_domain = domain;
}
@Override
public String gidToPrincipal(int id) {
__group g = _libc.getgrgid(id);
if( g == null)
return NOBODY_GROUP;
return addDomain(g.name);
}
@Override
public int principalToGid(String principal) {
__group g = _libc.getgrnam(stripDomain(principal));
if(g == null)
return NOBODY_GID;
return g.gid;
}
@Override
public int principalToUid(String principal) {
__password p = _libc.getpwnam(stripDomain(principal));
if(p == null)
return NOBODY_UID;
return p.uid;
}
@Override
public String uidToPrincipal(int id) {
__password p = _libc.getpwuid(id);
if(p == null)
return NOBODY_USER;
return addDomain(p.name);
}
@Override
public Subject login(Principal principal) {
__password p = _libc.getpwnam(stripDomain(principal.getName()));
if(p == null)
return Subjects.NOBODY;
return Subjects.of(p.uid, p.gid, groupsOf(p));
}
/**
* handle to libc.
*/
private final LibC _libc = (LibC) Native.loadLibrary("c", LibC.class);
private int[] groupsOf(__password pwrecord) {
boolean done = false;
int[] groups = new int[0];
while (!done) {
IntByReference ngroups = new IntByReference();
ngroups.setValue(groups.length);
if (_libc.getgrouplist(pwrecord.name, pwrecord.gid, groups, ngroups) < 0) {
groups = new int[ngroups.getValue()];
continue;
}
done = true;
}
return groups;
}
/*
* struct passwd equivalent as defined in <pwd.h>
*/
static public class __password extends Structure {
public String name;
public String passwd;
public int uid;
public int gid;
public String gecos;
public String dir;
public String shell;
}
/*
* struct group equivalent as defined in <pwd.h>
*/
static public class __group extends Structure {
public String name;
public String passwd;
public int gid;
public Pointer mem;
}
/*
* hook required functions from libc
*/
public interface LibC extends Library {
__password getpwnam(String name);
__password getpwuid(int id);
__group getgrnam(String name);
__group getgrgid(int id);
int getgrouplist(String user, int gid, int[] groups, IntByReference ngroups);
}
private String stripDomain(String s) {
int n = s.indexOf('@');
if (n != -1) {
return s.substring(0, n);
}
return s;
}
private String addDomain(String s) {
return s + "@" + _domain;
}
}
\ No newline at end of file
......@@ -16,17 +16,24 @@
*/
package org.dcache.chimera.nfs.v4;
import java.security.Principal;
import javax.security.auth.Subject;
import org.dcache.auth.Subjects;
/**
* Simple implementation of {@link NfsIdMapping} which converts number into
* string representation and vice versa.
*
* @since 0.0.4
*/
public class SimpleIdMap implements NfsIdMapping {
public class SimpleIdMap implements NfsIdMapping, NfsLoginService {
private static final int NOBODY_UID = -1;
private static final int NOBODY_GID = -1;
private static final int DEFAULT_UID = 1001;
private static final int DEFAULT_GID = 1001;
@Override
public int principalToGid(String principal) {
try {
......@@ -54,4 +61,9 @@ public class SimpleIdMap implements NfsIdMapping {
public String gidToPrincipal(int id) {
return Integer.toString(id);
}
@Override
public Subject login(Principal principal) {
return Subjects.of(DEFAULT_UID, DEFAULT_GID, new int[0]);
}
}
......@@ -22,7 +22,6 @@ import com.google.common.primitives.Ints;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.security.auth.kerberos.KerberosPrincipal;
import org.dcache.xdr.OncRpcException;
import org.dcache.xdr.RpcAuthError;
import org.dcache.xdr.RpcAuthException;
......@@ -118,9 +117,7 @@ public class GssProtocolFilter implements ProtocolFilter {
cred.getContext().dispose();
break;
case GssProc.RPCSEC_GSS_DATA:
call.getCredential().getSubject().getPrincipals().
add(new KerberosPrincipal(gssContext.getSrcName().toString()));
_log.log(Level.FINE, "RPCGSS_SEC: {0}", cred.getContext().getSrcName());
_log.log(Level.FINE, "RPCGSS_SEC: {0}",gssContext.getSrcName());
byte[] crc = Ints.toByteArray(authGss.getSequence());
crc = gssContext.getMIC(crc, 0, 4, new MessageProp(false));
authGss.setVerifier(new RpcAuthVerifier(authGss.type(), crc));
......
......@@ -16,10 +16,13 @@
*/
package org.dcache.xdr.gss;
import java.security.Principal;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import javax.security.auth.kerberos.KerberosPrincipal;
import org.dcache.chimera.nfs.v4.NfsLoginService;
import org.dcache.utils.Opaque;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
......@@ -32,14 +35,16 @@ public class GssSessionManager {
private static final Logger _log = Logger.getLogger(GssSessionManager.class.getName());
private final GSSManager gManager = GSSManager.getInstance();
private final GSSCredential _serviceCredential;
private final NfsLoginService _loginService;
public GssSessionManager() throws GSSException {
public GssSessionManager(NfsLoginService loginService) throws GSSException {
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
Oid krb5Mechanism = new Oid("1.2.840.113554.1.2.2");
_serviceCredential = gManager.createCredential(null,
GSSCredential.INDEFINITE_LIFETIME,
krb5Mechanism, GSSCredential.ACCEPT_ONLY);
_loginService = loginService;
}
private final Map<Opaque, RpcGssContext> sessions = new ConcurrentHashMap<Opaque, RpcGssContext>();
......@@ -66,6 +71,11 @@ public class GssSessionManager {
case GssProc.RPCSEC_GSS_DATA:
_log.fine("RPCSEC_GSS_DATA");
cred = sessions.get(new Opaque(gssAuth.getHandle()));
if(cred == null) {
throw new GSSException(GSSException.NO_CONTEXT);
}
Principal principal = new KerberosPrincipal(cred.getContext().getSrcName().toString());
gssAuth.getSubject().getPrincipals().addAll(_loginService.login(principal).getPrincipals());
break;
default:
throw new RuntimeException("Invalid GssProc: " + gssAuth.getProc());
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment