com.ikanow.aleph2.security.service.IkanowV1Realm.java Source code

Java tutorial

Introduction

Here is the source code for com.ikanow.aleph2.security.service.IkanowV1Realm.java

Source

/*******************************************************************************
 * Copyright 2015, The IKANOW Open Source Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package com.ikanow.aleph2.security.service;

import java.util.Collection;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.bson.types.ObjectId;

import scala.Tuple2;

import com.fasterxml.jackson.databind.JsonNode;
import com.google.inject.Inject;
import com.ikanow.aleph2.data_model.interfaces.data_services.IManagementDbService;
import com.ikanow.aleph2.data_model.interfaces.shared_services.ICrudService;
import com.ikanow.aleph2.data_model.interfaces.shared_services.IServiceContext;
import com.ikanow.aleph2.data_model.utils.CrudUtils;
import com.ikanow.aleph2.data_model.utils.CrudUtils.SingleQueryComponent;
import com.ikanow.aleph2.security.interfaces.IClearableRealmCache;
import com.ikanow.aleph2.security.interfaces.IRoleProvider;

public class IkanowV1Realm extends AuthorizingRealm implements IClearableRealmCache {
    private static final Logger logger = LogManager.getLogger(IkanowV1Realm.class);

    protected final IServiceContext _context;
    protected IManagementDbService _core_management_db = null;
    protected IManagementDbService _underlying_management_db = null;

    private ICrudService<AuthenticationBean> authenticationDb = null;
    private ICrudService<JsonNode> personDb = null;

    //   protected IRoleProvider roleProvider;

    private Set<IRoleProvider> roleProviders;

    @Inject
    public IkanowV1Realm(final IServiceContext service_context, CacheManager cacheManager,
            CredentialsMatcher matcher, Set<IRoleProvider> roleProviders) {
        super(cacheManager, matcher);
        _context = service_context;
        this.roleProviders = roleProviders;
        logger.debug("IkanowV1Realm name=" + getName());
    }

    @SuppressWarnings("unchecked")
    protected void initDb() {
        if (_core_management_db == null) {
            _core_management_db = _context.getCoreManagementDbService();
        }
        if (_underlying_management_db == null) {
            _underlying_management_db = _context.getService(IManagementDbService.class, Optional.empty()).get();
        }
        String authDboptions = "security.authentication/" + AuthenticationBean.class.getName();
        authenticationDb = _underlying_management_db
                .getUnderlyingPlatformDriver(ICrudService.class, Optional.of(authDboptions)).get();
        String personOptions = "social.person";
        personDb = _underlying_management_db
                .getUnderlyingPlatformDriver(ICrudService.class, Optional.of(personOptions)).get();
        logger.debug("PersonDB:" + personDb);
    }

    protected ICrudService<AuthenticationBean> getAuthenticationStore() {
        if (authenticationDb == null) {
            initDb();
        }
        return authenticationDb;
    }

    protected ICrudService<JsonNode> getPersonStore() {
        if (personDb == null) {
            initDb();
        }
        return personDb;
    }

    /**
     * This implementation of the interface expects the principals collection to return a String username keyed off of
     * this realm's {@link #getName() name}
     *
     * @see #getAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        //null usernames are invalid
        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }

        String username = (String) getAvailablePrincipal(principals);
        Set<String> roles = new HashSet<String>();
        Set<String> permissions = new HashSet<String>();

        for (IRoleProvider roleProvider : roleProviders) {
            Tuple2<Set<String>, Set<String>> t2 = roleProvider.getRolesAndPermissions(username);
            roles.addAll(t2._1());
            permissions.addAll(t2._2());
        } // for      

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
        info.addStringPermissions(permissions);
        return info;

    }

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();

        // Null username is invalid
        if (username == null) {
            throw new AccountException("Null usernames are not allowed by this realm.");
        }

        AuthenticationInfo info = null;
        try {

            SingleQueryComponent<AuthenticationBean> queryUsername = CrudUtils.anyOf(AuthenticationBean.class)
                    .when("username", username);
            ObjectId objectId = null;
            try {
                objectId = new ObjectId(username);
                // if we get here the username can be mapped to an id
                queryUsername = queryUsername.when("profileId", new ObjectId(username));
            } catch (Exception e) {
                // TODO: handle exception
            }

            Optional<AuthenticationBean> result = getAuthenticationStore().getObjectBySpec(queryUsername).get();
            if (result.isPresent()) {
                AuthenticationBean b = result.get();
                logger.debug("Loaded user info from db:" + b);
                info = new IkanowV1AuthenticationInfo(b);
            }
        } catch (Exception e) {
            final String message = "There was a Connection error while authenticating user [" + username + "]";
            logger.error(message, e);

            // Rethrow any errors as an authentication exception
            throw new AuthenticationException(message, e);
        } finally {
            // TODO close connection?
        }

        return info;
    }

    @Override
    public void clearAuthorizationCached(Collection<String> principalNames) {
        logger.debug("clearCachedAuthorizationInfo for " + principalNames);
        SimplePrincipalCollection principals = new SimplePrincipalCollection(principalNames,
                this.getClass().getName());
        super.doClearCache(principals);
    }

    @Override
    public void clearAllCaches() {
        logger.debug("clearAllCaches");

        Cache<Object, AuthenticationInfo> ac = getAuthenticationCache();
        if (ac != null) {
            ac.clear();
        }
        Cache<Object, AuthorizationInfo> ar = getAuthorizationCache();
        if (ar != null) {
            ar.clear();
        }

    }

}