org.opennaas.core.security.acl.ACLManager.java Source code

Java tutorial

Introduction

Here is the source code for org.opennaas.core.security.acl.ACLManager.java

Source

package org.opennaas.core.security.acl;

/*
 * #%L
 * OpenNaaS :: Core :: Security
 * %%
 * Copyright (C) 2007 - 2014 Fundaci Privada i2CAT, Internet i Innovaci a Catalunya
 * %%
 * 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 3 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 General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Properties;
import java.util.UUID;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opennaas.core.resources.Resource;
import org.opennaas.core.resources.configurationadmin.ConfigurationAdminUtil;
import org.opennaas.core.security.Activator;
import org.opennaas.core.security.persistence.SecurityRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.core.context.SecurityContextHolder;

/**
 * 
 * @author Julio Carlos Barrera
 * 
 */
public class ACLManager implements IACLManager {

    private static Log log = LogFactory.getLog(ACLManager.class);

    // OpenNaaS-Security SQL scripts to initialize Spring Security ACLs SQL schema
    private static String SQL_ACLS;

    // Properties containing users to add to DB
    private String usersPropertiesFile;
    private static final String usersPropertiesUsersPrefix = "users.";
    private static final String usersPropertiesUsersSize = "size";

    private SecurityRepository securityRepository;

    @Autowired
    private MutableAclService aclService;
    @Autowired
    private PermissionEvaluator permissionEvaluator;

    public void init() throws IOException {
        initializeSpringSecurityAclDB();
        initializeUsers();
        initializeClasses();
        registerOSGiService();
    }

    private void initializeSpringSecurityAclDB() {
        log.debug("Reading OpenNaaS-Security SQL init scripts contents...");
        SQL_ACLS = Activator.getBundleTextFileContents("/security_db_scripts/acls.sql");
        log.debug("OpenNaaS-Security SQL init scripts contents read.");

        log.debug("Executing OpenNaaS-Security SQL init scripts...");
        executeSqlQuery(SQL_ACLS);
        log.debug("OpenNaaS-Security SQL init scripts executed.");
    }

    private void initializeUsers() throws IOException, NumberFormatException {
        Properties usersProperties = getProperties(usersPropertiesFile);

        // getting users.size
        int usersSize = Integer
                .parseInt(usersProperties.getProperty(usersPropertiesUsersPrefix + usersPropertiesUsersSize));

        for (int i = 0; i < usersSize; i++) {
            // adding users.{i}
            String user = usersProperties.getProperty(usersPropertiesUsersPrefix + i);
            if (user != null) {
                insertAclSid(i, true, new PrincipalSid(user));
            }
        }
    }

    public Properties getProperties(final String propertyFile) throws IOException {
        final Properties properties = new Properties();
        final URL resource = Activator.class.getClassLoader().getResource(propertyFile + ".properties");

        if (null == resource) {
            throw new FileNotFoundException(propertyFile + " could not be found");
        }

        final InputStream propertyStream = resource.openStream();
        properties.load(propertyStream);
        return properties;
    }

    private void initializeClasses() {
        insertAclClass(0, Resource.class);
    }

    private void insertAclSid(long id, boolean isPrincipal, PrincipalSid sid) {
        String query = "insert into acl_sid (id, principal, sid) values ( " + id + ", " + (isPrincipal ? 1 : 0)
                + ", '" + sid.getPrincipal() + "');";
        executeSqlQuery(query);
    }

    private void insertAclClass(long id, Class<?> clazz) {
        String query = "insert into acl_class (id, class) values ( " + id + ", '" + clazz.getName() + "');";
        executeSqlQuery(query);
    }

    private void insertAcl(long id, PrincipalSid principalSid, Permission permission) {
        ObjectIdentity oi = new ObjectIdentityImpl(Resource.class, id);

        // Create or update the relevant ACL
        MutableAcl acl = null;
        try {
            acl = (MutableAcl) aclService.readAclById(oi);
        } catch (NotFoundException nfe) {
            acl = aclService.createAcl(oi);
        }

        // Now grant some permissions via an access control entry (ACE)
        acl.insertAce(acl.getEntries().size(), permission, principalSid, true);
        aclService.updateAcl(acl);
    }

    @Override
    public void secureResource(String resourceId, String user) {
        insertAcl(ResourceIdToSecureId(resourceId), new PrincipalSid(user), BasePermission.READ);
    }

    @Override
    public Boolean isResourceAccessible(String resourceId) {
        return permissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(),
                ResourceIdToSecureId(resourceId), Resource.class.getName(), BasePermission.READ);
    }

    private static long ResourceIdToSecureId(String resourceId) {
        // generate a long secure Id (64 bits) from Resource ID (128 bits)to use in ACL DB
        return UUID.fromString(resourceId).getMostSignificantBits();
    }

    private void executeSqlQuery(String sqlQuery) {
        log.debug("Executing SQL query: [ " + sqlQuery + " ]");
        EntityManager em = securityRepository.getEntityManager();
        EntityTransaction et = em.getTransaction();
        et.begin();
        try {
            em.createNativeQuery(sqlQuery).executeUpdate();
            em.flush();
            et.commit();
            log.debug("SQL query executed.");
        } catch (Exception e) {
            log.error("Error executing SQL query, rollbacking", e);
            et.rollback();
        }
    }

    /**
     * It is necessary to register the OSGi service here, because OSGi ConfigurationAdmin service has access to "ws.rest.url", required to register
     * our REST API
     * 
     * @throws IOException
     */
    private void registerOSGiService() throws IOException {
        Dictionary<String, String> props = new Hashtable<String, String>();
        ConfigurationAdminUtil configurationAdmin = new ConfigurationAdminUtil(Activator.getBundleContext());
        String url = configurationAdmin.getProperty("org.opennaas", "ws.rest.url");

        if (props != null) {
            props.put("service.exported.interfaces", "*");
            props.put("service.exported.configs", "org.apache.cxf.rs");
            props.put("service.exported.intents", "HTTP");
            props.put("org.apache.cxf.rs.httpservice.context", url + "/aclmanager");
            props.put("org.apache.cxf.rs.address", "/");
            props.put("org.apache.cxf.httpservice.requirefilter", "true");
        }
        log.info("Registering ws in url: " + props.get("org.apache.cxf.rs.httpservice.context"));
        Activator.getBundleContext().registerService(IACLManager.class.getName(), this, props);
    }

    public void setUsersPropertiesFile(String usersPropertiesFile) {
        this.usersPropertiesFile = usersPropertiesFile;
    }

    public void setSecurityRepository(SecurityRepository securityRepository) {
        this.securityRepository = securityRepository;
    }

    public void setAclService(MutableAclService aclService) {
        this.aclService = aclService;
    }

    public void setPermissionEvaluator(PermissionEvaluator permissionEvaluator) {
        this.permissionEvaluator = permissionEvaluator;
    }

}