package dmg.cells.services.login.user ;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import dmg.cells.nucleus.CellAdapter;
import dmg.cells.nucleus.CellMessage;
import dmg.cells.services.login.Crypt;
import org.dcache.util.Args;
import dmg.util.Authorizable;
import dmg.util.UserPasswords;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Arrays.asList;
/**
**
*
*
* @author Patrick Fuhrmann
* @version 0.1, 15 Feb 1998
*
*/
public class AclCell
extends CellAdapter {
private static final Logger _log =
LoggerFactory.getLogger(AclCell.class);
private AclDb _aclDb;
private UserRelationable _userDb;
private UserMetaDb _userMetaDb;
private UserPasswords _sysPassword;
private UserPasswords _egPassword;
private Crypt _crypt = new Crypt() ;
public AclCell(String name, String argString)
{
super(name, argString);
}
@Override
protected void starting()
{
Args args = getArgs();
checkArgument(args.argc() >= 1, "Usage : ... <dbPath>");
File dbBase = new File(args.argv(0));
_aclDb = new AclDb(new File(dbBase, "acls"));
_userDb = new InMemoryUserRelation(new FileUserRelation(new File(dbBase, "relations")));
_userMetaDb = new UserMetaDb(new File(dbBase, "meta"));
UserAdminCommands uac = new UserAdminCommands(_userDb, _aclDb, _userMetaDb);
addCommandListener(uac);
setCommandExceptionEnabled(true);
//
// read the password file information
//
String tmp;
if ((tmp = args.getOpt("syspassword")) != null) {
_sysPassword = new UserPasswords(new File(tmp));
_log.info("using as SystemPasswordfile : " + tmp);
}
if ((tmp = args.getOpt("egpassword")) != null) {
_egPassword = new UserPasswords(new File(tmp));
_log.info("using as EgPasswordfile : " + tmp);
}
}
//
// for now we also serve the password checking request
//
@Override
public void messageArrived( CellMessage msg ){
Serializable obj = msg.getMessageObject() ;
Serializable answer;
try{
_log.info( "Message type : "+obj.getClass() ) ;
if( ( obj instanceof Object [] ) &&
( ((Object[])obj).length >= 3 ) &&
( ((Object[])obj)[0].equals("request") ) ){
Object [] request = (Object[])obj ;
String user = request[1] == null ?
"unknown" : (String)request[1] ;
String command = (String)request[2] ;
_log.info('>' + command + "< request from " + user ) ;
try{
switch (command) {
case "check-password":
answer = acl_check_password(request);
break;
case "check-permission":
answer = acl_check_permission(request);
break;
case "get-metainfo":
answer = acl_get_metainfo(request);
break;
default:
throw new Exception("Command not found : " + command);
}
}catch( Exception xe ){
throw new Exception( "Problem : "+xe ) ;
}
}else{
String r = "Illegal message object received from : "+
msg.getSourcePath() ;
_log.warn( r ) ;
throw new Exception( r ) ;
}
}catch(Exception iex ){
answer = iex ;
}
if( answer instanceof Object [] ) {
((Object[]) answer)[0] = "response";
}
msg.revertDirection() ;
msg.setMessageObject(answer) ;
sendMessage(msg) ;
}
///////////////////////////////////////////////////////////////////////////
//
// r[0] : request
// r[1] : <requestor>
// r[2] : get-metainfo
// r[3] : <user>
// r[4] : <key>[,<key>[...]]
//
// checks : nothing
//
// response
//
// r[0] : response
// r[1] : <requestor>
// r[2] : get-metainfo
// r[3] : <user>
// r[4] : <key>[,<key>[...]]
// r[5] : <valueOfKey1>
// r[6] : <valueOfKey2>
// r[7] : ...
//
private Serializable
acl_get_metainfo( Object [] request )
{
if( ( request.length < 5 ) ||
( request[3] == null ) ||
( request[4] == null ) ) {
throw new
IllegalArgumentException(
"Not enough or illegal arguments for 'check-password'");
}
String userName = request[3].toString() ;
UserMetaDictionary dict = _userMetaDb.getDictionary(userName) ;
if( dict == null ) {
throw new
IllegalArgumentException(
"No such user : " + userName);
}
List<Object> result = new ArrayList<>(asList(request).subList(0, 5));
StringTokenizer st = new StringTokenizer( request[4].toString() , "," ) ;
while( st.hasMoreTokens() ){
result.add(dict.valueOf(st.nextToken())) ;
}
return result.toArray(new Object[result.size()]);
}
///////////////////////////////////////////////////////////////////////////
//
// r[0] : request
// r[1] : <anything>
// r[2] : check-password
// r[3] : <user>
// r[4] : <password>[plainText]
//
// checks : nothing
//
// response
//
// r[0] : response
// r[1] : <user>
// r[2] : check-password
// r[3] : <user>
// r[4] : <password>[plainText]
// r[5] : Boolean(true/false)
//
private Serializable
acl_check_password( Object [] request )
{
if( request.length < 5 ) {
throw new
IllegalArgumentException(
"Not enough arguments for 'check-password'");
}
Object [] response = new Object[6] ;
System.arraycopy(request, 0, response, 0, 5);
response[1] = request[3] ;
String userName = (String)request[3] ;
String password = (String)request[4] ;
response[5] = matchPassword(userName, password);
return response ;
}
///////////////////////////////////////////////////////////////////////////
//
// r[0] : request
// r[1] : <anything>
// r[2] : check-permission
// r[3] : <principal>
// r[4] : <acl>
//
// checks : nothing
//
// response
//
// r[0] : response
// r[1] : <user>
// r[2] : check-permission
// r[3] : <principal>
// r[4] : <acl>
// r[5] : Boolean(true/false)
//
private Serializable
acl_check_permission( Object [] request )
{
if( request.length < 5 ) {
throw new
IllegalArgumentException(
"Not enough arguments for 'check-permission'");
}
Object [] response = new Object[6] ;
System.arraycopy(request, 0, response, 0, 5);
response[1] = request[3] ;
String userName = (String)request[3] ;
String acl = (String)request[4] ;
response[5] = checkPermission(userName, acl);
return response ;
}
private boolean checkPermission( String user , String acl ) {
if( user.equals("admin") ) {
return true;
}
try{
if( _aclDb.check( acl , user , _userDb ) ) {
return true;
}
}catch(Exception ee ){}
try{
if( _aclDb.check( "super.access" , user , _userDb ) ) {
return true;
}
}catch(Exception ee ){}
return false ;
}
private static final String DUMMY_ADMIN = "5t2Hw7lNqVock" ;
private boolean matchPassword( String userName , String password ){
String pswd;
updatePassword() ;
try{
if( userName.equals("admin" ) ){
if( ( _sysPassword == null ) ||
( ( pswd = _sysPassword.getPassword(userName) ) == null ) ){
if( ( _egPassword == null ) ||
( ( pswd = _egPassword.getPassword(userName) ) == null ) ){
pswd = DUMMY_ADMIN ;
}
}
return _crypt.crypt( pswd , password ).equals(pswd) ;
}else{
//
// the user must have been created.
//
UserMetaDictionary dict = _userMetaDb.getDictionary(userName) ;
if( dict == null ) {
return false;
}
//
// check for login disabled.
//
String dis = dict.valueOf("login") ;
if( ( dis != null ) && ( dis.equals("no") ) ) {
return false;
}
if( ( _sysPassword == null ) ||
( ( pswd = _sysPassword.getPassword(userName) ) == null ) ){
if( ( _egPassword == null ) ||
( ( pswd = _egPassword.getPassword(userName) ) == null ) ){
return false ;
}
}
return _crypt.crypt( pswd , password ).equals(pswd) ;
}
}catch( Throwable t ){
_log.warn( "Found : "+t ) ;
}
return false ;
}
private void updatePassword(){
try{
if( _sysPassword != null ) {
_sysPassword.update();
}
}catch(Exception ee ){
_log.warn( "Updating failed : "+_sysPassword ) ;
}
try{
if( _egPassword != null ) {
_egPassword.update();
}
}catch(Exception ee ){
_log.warn( "Updating failed : "+_egPassword ) ;
}
}
/////////////////////////////////////////////////////////////
//
// the interpreter
//
private void checkPermission( Args args , String acl ) throws Exception {
if( ! ( args instanceof Authorizable ) ) {
throw new
AclPermissionException("Command not authorizable");
}
String user = ((Authorizable)args).getAuthorizedPrincipal() ;
if( user.equals("admin") ) {
return;
}
try{
if( _aclDb.check( "super.access" , user , _userDb ) ) {
return;
}
}catch(Exception ee ){}
if( ! _aclDb.check(acl,user,_userDb) ) {
throw new
AclPermissionException("Acl >" + acl + "< negative for " + user);
}
}
public String ac_interrupted( Args args )
{
return "\n" ;
}
public static final String hh_set_passwd =
"[-user=<userName>] [-old=<oldPasswd>] newPswd verifyPswd";
public String ac_set_passwd_$_2( Args args )throws Exception {
if( _egPassword == null ) {
throw new
AclPermissionException("No private password file found");
}
if( ! ( args instanceof Authorizable ) ) {
throw new
AclPermissionException("Command not authorizable");
}
String pswd1 = args.argv(0) ;
String pswd2 = args.argv(1) ;
if( ! pswd1.equals( pswd2 ) ) {
throw new
IllegalArgumentException("pswd1 doesn't match pswd2");
}
String auth = ((Authorizable)args).getAuthorizedPrincipal() ;
String user = args.getOpt("user") ;
user = user == null ? auth : user ;
String old = args.getOpt("old");
String acl = "user."+user+".setpassword" ;
String [] record;
if( ! ( auth.equals("admin" ) || _aclDb.check( acl , auth , _userDb ) ) ){
if( auth.equals(user) ){
if( old == null ) {
throw new
IllegalArgumentException("-old=<oldPassword> option missing");
}
}else{
throw new
AclPermissionException( "Acl >"+acl+"< negative for "+auth ) ;
}
if( ( pswd2 = _egPassword.getPassword(user) ) == null ) {
throw new
IllegalArgumentException("User not found in private passwd file");
}
if( ! _crypt.crypt( pswd2 , old ).equals(pswd2) ) {
throw new
IllegalArgumentException("Old password doesn't match");
}
record = _egPassword.getRecord(user) ;
if( record == null ) {
throw new
IllegalArgumentException("User " + user + " doesn't exist");
}
}else{
record = _egPassword.getRecord(user) ;
if( record == null ){
record = new String[2] ;
record[0] = user ;
}
}
record[1] = _crypt.crypt( user.substring(0,2) , pswd1 ) ;
_egPassword.addRecord( record ) ;
_egPassword.commit() ;
return "" ;
}
}