Package org.exist.security.internal

Source Code of org.exist.security.internal.RealmImpl

/*
*  eXist Open Source Native XML Database
*  Copyright (C) 2010-2011 The eXist Project
*  http://exist-db.org
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public License
*  as published by the Free Software Foundation; either version 2
*  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 Lesser General Public License for more details.
*  You should have received a copy of the GNU Lesser General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*  $Id$
*/
package org.exist.security.internal;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.exist.EXistException;
import org.exist.config.Configuration;
import org.exist.config.ConfigurationException;
import org.exist.config.Reference;
import org.exist.config.ReferenceImpl;
import org.exist.security.AXSchemaType;
import org.exist.security.AbstractAccount;
import org.exist.security.AbstractPrincipal;
import org.exist.security.AbstractRealm;
import org.exist.security.Account;
import org.exist.security.AuthenticationException;
import org.exist.security.EXistSchemaType;
import org.exist.security.Group;
import org.exist.security.PermissionDeniedException;
import org.exist.security.SecurityManager;
import org.exist.security.Subject;
import org.exist.security.UUIDGenerator;
import org.exist.security.internal.aider.UserAider;
import org.exist.storage.BrokerPool;
import org.exist.storage.DBBroker;
import org.exist.storage.txn.TransactionManager;
import org.exist.storage.txn.Txn;
import org.exist.xmldb.XmldbURI;

/**
* @author <a href="mailto:shabanovd@gmail.com">Dmitriy Shabanov</a>
*
*/
public class RealmImpl extends AbstractRealm {
 
    public static String ID = "exist"; //TODO: final "eXist-db";

    private final static Logger LOG = Logger.getLogger(RealmImpl.class);

    static public void setPasswordRealm(String value) {
        ID = value;
    }

    public final static int SYSTEM_ACCOUNT_ID = 1048575;
    public final static int ADMIN_ACCOUNT_ID = 1048574;
    public final static int GUEST_ACCOUNT_ID = 1048573;
    public final static int UNKNOWN_ACCOUNT_ID = 1048572;
    public final static int INITIAL_LAST_ACCOUNT_ID = 10;

    public final static int DBA_GROUP_ID = 1048575;
    public final static int GUEST_GROUP_ID = 1048574;
    public final static int UNKNOWN_GROUP_ID = 1048573;
    public final static int INITIAL_LAST_GROUP_ID = 10;

    protected final AccountImpl ACCOUNT_SYSTEM;
    protected final AccountImpl ACCOUNT_UNKNOWN;
   
    protected final GroupImpl GROUP_DBA;
    protected final GroupImpl GROUP_GUEST;
    protected final GroupImpl GROUP_UNKNOWN;
   
    private final static String DEFAULT_ADMIN_PASSWORD = "";
    private final static String DEFAULT_GUEST_PASSWORD = "guest";

    //@ConfigurationFieldAsElement("allow-guest-authentication")
    public boolean allowGuestAuthentication = true;

    protected RealmImpl(final SecurityManagerImpl sm, final Configuration config) throws ConfigurationException { //, Configuration conf

      super(sm, config);

      sm.lastUserId = INITIAL_LAST_ACCOUNT_ID;     //TODO this is horrible!
      sm.lastGroupId = INITIAL_LAST_GROUP_ID;    //TODO this is horrible!
       
        //DBA group
        GROUP_DBA = new GroupImpl(this, DBA_GROUP_ID, SecurityManager.DBA_GROUP);
        GROUP_DBA.setManagers(new ArrayList<Reference<SecurityManager, Account>>(){
            { add(new ReferenceImpl<SecurityManager, Account>(sm, "getAccount", SecurityManager.DBA_USER)); }
        });
        GROUP_DBA.setMetadataValue(EXistSchemaType.DESCRIPTION, "Database Administrators");
      sm.addGroup(GROUP_DBA.getId(), GROUP_DBA);
        registerGroup(GROUP_DBA);
        //sm.groupsById.put(GROUP_DBA.getId(), GROUP_DBA);
      //groupsByName.put(GROUP_DBA.getName(), GROUP_DBA);
       
        //System account
      ACCOUNT_SYSTEM = new AccountImpl(this, SYSTEM_ACCOUNT_ID, SecurityManager.SYSTEM, "", GROUP_DBA, true);
        ACCOUNT_SYSTEM.setMetadataValue(AXSchemaType.FULLNAME, SecurityManager.SYSTEM);
        ACCOUNT_SYSTEM.setMetadataValue(EXistSchemaType.DESCRIPTION, "System Internals");
        sm.addUser(ACCOUNT_SYSTEM.getId(), ACCOUNT_SYSTEM);
        registerAccount(ACCOUNT_SYSTEM);
      //sm.usersById.put(ACCOUNT_SYSTEM.getId(), ACCOUNT_SYSTEM);
      //usersByName.put(ACCOUNT_SYSTEM.getName(), ACCOUNT_SYSTEM);
       
        //guest group
        GROUP_GUEST = new GroupImpl(this, GUEST_GROUP_ID, SecurityManager.GUEST_GROUP);
        GROUP_GUEST.setManagers(new ArrayList<Reference<SecurityManager, Account>>(){
            { add(new ReferenceImpl<SecurityManager, Account>(sm, "getAccount", SecurityManager.DBA_USER)); }
        });
        GROUP_GUEST.setMetadataValue(EXistSchemaType.DESCRIPTION, "Anonymous Users");
        sm.addGroup(GROUP_GUEST.getId(), GROUP_GUEST);
        registerGroup(GROUP_GUEST);
      //sm.groupsById.put(GROUP_GUEST.getId(), GROUP_GUEST);
      //groupsByName.put(GROUP_GUEST.getName(), GROUP_GUEST);
       
        //unknown account and group
        GROUP_UNKNOWN = new GroupImpl(this, UNKNOWN_GROUP_ID, "");
      ACCOUNT_UNKNOWN = new AccountImpl(this, UNKNOWN_ACCOUNT_ID, "", (String)null, GROUP_UNKNOWN);
       
        //XXX: GROUP_DBA._addManager(ACCOUNT_ADMIN);
      //XXX: GROUP_GUEST._addManager(ACCOUNT_ADMIN);
    }

    @Override
    public void start(final DBBroker broker) throws EXistException {
        super.start(broker);
        try {
            createAdminAndGuestIfNotExist(broker);
        } catch(final PermissionDeniedException pde) {
            final boolean exportOnly =  (Boolean) broker.getConfiguration().getProperty(BrokerPool.PROPERTY_EXPORT_ONLY, false);
            if(!exportOnly) {
              throw new EXistException(pde.getMessage(), pde);
            }
        }
    }
   
    private void createAdminAndGuestIfNotExist(final DBBroker broker) throws EXistException, PermissionDeniedException {
     
        //Admin account
        if(getSecurityManager().getAccount(ADMIN_ACCOUNT_ID) == null) {
            //AccountImpl actAdmin = new AccountImpl(broker, this, ADMIN_ACCOUNT_ID, SecurityManager.DBA_USER, "", GROUP_DBA, true);
            final UserAider actAdmin = new UserAider(ADMIN_ACCOUNT_ID, getId(), SecurityManager.DBA_USER);
            actAdmin.setPassword(DEFAULT_ADMIN_PASSWORD);
            actAdmin.setMetadataValue(AXSchemaType.FULLNAME, SecurityManager.DBA_USER);
            actAdmin.setMetadataValue(EXistSchemaType.DESCRIPTION, "System Administrator");
            actAdmin.addGroup(SecurityManager.DBA_GROUP);
            getSecurityManager().addAccount(broker, actAdmin);
        }

        //Guest account
        if(getSecurityManager().getAccount(GUEST_ACCOUNT_ID) == null) {
            //AccountImpl actGuest = new AccountImpl(broker, this, GUEST_ACCOUNT_ID, SecurityManager.GUEST_USER, SecurityManager.GUEST_USER, GROUP_GUEST, false);
            final UserAider actGuest = new UserAider(GUEST_ACCOUNT_ID, getId(), SecurityManager.GUEST_USER);
            actGuest.setMetadataValue(AXSchemaType.FULLNAME, SecurityManager.GUEST_USER);
            actGuest.setMetadataValue(EXistSchemaType.DESCRIPTION, "Anonymous User");
            actGuest.setPassword(DEFAULT_GUEST_PASSWORD);
            actGuest.addGroup(SecurityManager.GUEST_GROUP);
            getSecurityManager().addAccount(broker, actGuest);
        }
    }
   
    @Override
    public String getId() {
        return ID;
    }

    @Override
    public boolean deleteAccount(final Account account) throws PermissionDeniedException, EXistException {
        if(account == null) {
            return false;
        }
       
        usersByName.modify2E(new PrincipalDbModify2E<Account, PermissionDeniedException, EXistException>(){
            @Override
            public void execute(Map<String, Account> principalDb) throws PermissionDeniedException, EXistException {
                final AbstractAccount remove_account = (AbstractAccount)principalDb.get(account.getName());
                if(remove_account == null){
                    throw new IllegalArgumentException("No such account exists!");
                }

                DBBroker broker = null;
                try {
                    broker = getDatabase().get(null);
                    final Account user = broker.getSubject();

                    if(!(account.getName().equals(user.getName()) || user.hasDbaRole()) ) {
                        throw new PermissionDeniedException("You are not allowed to delete '" +account.getName() + "' user");
                    }

                    remove_account.setRemoved(true);
                    remove_account.setCollection(broker, collectionRemovedAccounts, XmldbURI.create(UUIDGenerator.getUUID()+".xml"));

                    final TransactionManager transaction = getDatabase().getTransactionManager();
                    Txn txn = null;
                    try {
                        txn = transaction.beginTransaction();

                        collectionAccounts.removeXMLResource(txn, broker, XmldbURI.create( remove_account.getName() + ".xml"));

                        transaction.commit(txn);
                    } catch(final Exception e) {
                        transaction.abort(txn);
                        e.printStackTrace();
                        LOG.debug("loading configuration failed: " + e.getMessage());
                    } finally {
                        transaction.close(txn);
                    }

                    getSecurityManager().addUser(remove_account.getId(), remove_account);
                    principalDb.remove(remove_account.getName());
                } finally {
                    getDatabase().release(broker);
                }
            }
        });
       
        return true;
    }

    @Override
    public boolean deleteGroup(final Group group) throws PermissionDeniedException, EXistException {
        if(group == null)
            {return false;}
       
        groupsByName.modify2E(new PrincipalDbModify2E<Group, PermissionDeniedException, EXistException>(){
            @Override
            public void execute(Map<String, Group> principalDb) throws PermissionDeniedException, EXistException {
       
              final AbstractPrincipal remove_group = (AbstractPrincipal)principalDb.get(group.getName());
              if(remove_group == null)
                    {throw new IllegalArgumentException("Group does '"+group.getName()+"' not exist!");}
   
              final DBBroker broker = getDatabase().getActiveBroker();
                final Subject subject = broker.getSubject();
               
                ((Group)remove_group).assertCanModifyGroup(subject);
   
                remove_group.setRemoved(true);
                remove_group.setCollection(broker, collectionRemovedGroups, XmldbURI.create(UUIDGenerator.getUUID() + ".xml"));
   
                final TransactionManager transaction = getDatabase().getTransactionManager();
                Txn txn = null;
                try {
                    txn = transaction.beginTransaction();

                    collectionGroups.removeXMLResource(txn, broker, XmldbURI.create(remove_group.getName() + ".xml" ));

                    transaction.commit(txn);
                } catch (final Exception e) {
                    transaction.abort(txn);
                    LOG.debug(e);
                } finally {
                    transaction.close(txn);
                }

                getSecurityManager().addGroup(remove_group.getId(), (Group)remove_group);
                principalDb.remove(remove_group.getName());
            }
        });
       
        return true;
    }

    @Override
    public Subject authenticate(final String accountName, Object credentials) throws AuthenticationException {
        final Account account = getAccount(accountName);
       
        if(account == null) {
            throw new AuthenticationException(AuthenticationException.ACCOUNT_NOT_FOUND, "Account '" + accountName + "' not found.");
        }
       
        if("SYSTEM".equals(accountName) || (!allowGuestAuthentication && "guest".equals(accountName))) {
            throw new AuthenticationException(AuthenticationException.ACCOUNT_NOT_FOUND, "Account '" + accountName + "' can not be used.");
        }

        if(!account.isEnabled()) {
            throw new AuthenticationException(AuthenticationException.ACCOUNT_LOCKED, "Account '" + accountName + "' is disabled.");
        }

        final Subject subject = new SubjectImpl((AccountImpl) account, credentials);
        if(!subject.isAuthenticated()) {
            throw new AuthenticationException(AuthenticationException.WRONG_PASSWORD, "Wrong password for user [" + accountName + "] ");
        }
           
        return subject;
    }

    @Override
    public List<String> findUsernamesWhereUsernameStarts(final String startsWith) {

        return usersByName.read(new PrincipalDbRead<Account, List<String>>(){
            @Override
            public List<String> execute(Map<String, Account> principalDb) {
                final List<String> userNames = new ArrayList<String>();
                for(final String userName : principalDb.keySet()) {
                    if(userName.startsWith(startsWith)) {
                        userNames.add(userName);
                    }
                }
                return userNames;
            }
        });
    }
   
    @Override
    public List<String> findGroupnamesWhereGroupnameStarts(final String startsWith) {

        return groupsByName.read(new PrincipalDbRead<Group, List<String>>(){
            @Override
            public List<String> execute(Map<String, Group> principalDb) {
                final List<String> groupNames = new ArrayList<String>();
                for(final String groupName : principalDb.keySet()) {
                    if(groupName.startsWith(startsWith)) {
                        groupNames.add(groupName);
                    }
                }
                return groupNames;
            }
        });
    }
   
    @Override
    public Collection<? extends String> findGroupnamesWhereGroupnameContains(final String fragment) {
        return groupsByName.read(new PrincipalDbRead<Group, List<String>>(){
            @Override
            public List<String> execute(Map<String, Group> principalDb) {
                final List<String> groupNames = new ArrayList<String>();
                for(final String groupName : principalDb.keySet()) {
                    if(groupName.indexOf(fragment) > -1) {
                        groupNames.add(groupName);
                    }
                }
                return groupNames;
            }
        });
    }

    @Override
    public List<String> findAllGroupNames() {
        return groupsByName.read(new PrincipalDbRead<Group, List<String>>(){
            @Override
            public List<String> execute(Map<String, Group> principalDb) {
                return new ArrayList<String>(principalDb.keySet());
            }
        });
    }
   
    @Override
    public List<String> findAllUserNames() {
        return usersByName.read(new PrincipalDbRead<Account, List<String>>(){
            @Override
            public List<String> execute(Map<String, Account> principalDb) {
                return new ArrayList<String>(principalDb.keySet());
            }
        });
    }

    @Override
    public List<String> findAllGroupMembers(final String groupName) {
        return usersByName.read(new PrincipalDbRead<Account, List<String>>(){
            @Override
            public List<String> execute(Map<String, Account> principalDb) {
                final List<String> groupMembers = new ArrayList<String>();
                for(final Account account : principalDb.values()) {
                    if(account.hasGroup(groupName)) {
                        groupMembers.add(account.getName());
                    }
                }
                return groupMembers;
            }
        });
    }

    @Override
    public List<String> findUsernamesWhereNameStarts(String startsWith) {
        return new ArrayList<String>();    //TODO at present exist users cannot have personal name details
    }

    @Override
    public List<String> findUsernamesWhereNamePartStarts(String startsWith) {
        return new ArrayList<String>();    //TODO at present exist users cannot have personal name details
    }
}
TOP

Related Classes of org.exist.security.internal.RealmImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.