org.qi4j.library.shiro.domain.passwords.PasswordRealmMixin.java Source code

Java tutorial

Introduction

Here is the source code for org.qi4j.library.shiro.domain.passwords.PasswordRealmMixin.java

Source

/*
 * Copyright (c) 2012, Paul Merlin. All Rights Reserved.
 *
 * 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 org.qi4j.library.shiro.domain.passwords;

import java.util.Set;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.DefaultPasswordService;
import org.apache.shiro.authc.credential.PasswordMatcher;
import org.apache.shiro.authc.credential.PasswordService;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.Authorizer;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.DefaultHashService;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;
import org.qi4j.api.configuration.Configuration;
import org.qi4j.api.injection.scope.Structure;
import org.qi4j.api.injection.scope.This;
import org.qi4j.api.query.QueryBuilder;
import org.qi4j.api.service.ServiceActivation;
import org.qi4j.api.structure.Module;
import org.qi4j.api.unitofwork.UnitOfWork;
import org.qi4j.library.shiro.Shiro;
import org.qi4j.library.shiro.domain.permissions.RoleAssignee;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.qi4j.api.query.QueryExpressions.eq;
import static org.qi4j.api.query.QueryExpressions.templateFor;

public class PasswordRealmMixin extends AuthorizingRealm
        implements Realm, Authorizer, PasswordService, ServiceActivation {

    private static final Logger LOG = LoggerFactory.getLogger(Shiro.LOGGER_NAME);

    @Structure
    private Module module;

    @This
    private Configuration<PasswordRealmConfiguration> configuration;

    private final DefaultPasswordService passwordService;

    public PasswordRealmMixin() {
        super();
        passwordService = new DefaultPasswordService();
        PasswordMatcher matcher = new PasswordMatcher();
        matcher.setPasswordService(passwordService);
        setCredentialsMatcher(matcher);
    }

    @Override
    public void activateService() throws Exception {
        configuration.refresh();
        PasswordRealmConfiguration config = configuration.get();
        String algorithm = config.hashAlgorithmName().get();
        Integer iterations = config.hashIterationsCount().get();
        if (algorithm != null || iterations != null) {
            DefaultHashService hashService = (DefaultHashService) passwordService.getHashService();
            if (algorithm != null) {
                hashService.setHashAlgorithmName(algorithm);
            }
            if (iterations != null) {
                hashService.setHashIterations(iterations);
            }
        }
    }

    @Override
    public void passivateService() throws Exception {
    }

    @Override
    public String encryptPassword(Object plaintextPassword) throws IllegalArgumentException {
        return passwordService.encryptPassword(plaintextPassword);
    }

    @Override
    public boolean passwordsMatch(Object submittedPlaintext, String encrypted) {
        return passwordService.passwordsMatch(submittedPlaintext, encrypted);
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UnitOfWork uow = module.newUnitOfWork();
        try {

            String username = ((UsernamePasswordToken) token).getUsername();
            PasswordSecurable account = findPasswordSecurable(uow, username);
            if (account == null) {
                LOG.debug("Unknown subject identifier: {}" + username);
                return null;
            }
            LOG.debug("Found account for {}: {}", username, account);
            return new SimpleAuthenticationInfo(account.subjectIdentifier().get(), account.password().get(),
                    getName());

        } finally {
            uow.discard();
        }
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        UnitOfWork uow = module.newUnitOfWork();
        try {

            String username = getAvailablePrincipal(principals).toString();
            RoleAssignee roleAssignee = findRoleAssignee(uow, username);
            if (roleAssignee == null) {
                LOG.debug("No authorization info for {}", username);
                return null;
            }
            LOG.debug("Found role assignee for {}: {}", username, roleAssignee);
            Set<String> roleNames = roleAssignee.roleNames();
            Set<String> permissionStrings = roleAssignee.permissionStrings();
            LOG.debug("Found role assignee has the following roles: {}", roleNames);
            LOG.debug("Found role assignee has the following permissions: {}", permissionStrings);
            SimpleAuthorizationInfo atzInfo = new SimpleAuthorizationInfo(roleNames);
            atzInfo.setStringPermissions(permissionStrings);
            return atzInfo;

        } finally {
            uow.discard();
        }
    }

    private PasswordSecurable findPasswordSecurable(UnitOfWork uow, String username) {
        QueryBuilder<PasswordSecurable> builder = module.newQueryBuilder(PasswordSecurable.class);
        builder = builder.where(eq(templateFor(PasswordSecurable.class).subjectIdentifier(), username));
        return uow.newQuery(builder).find();
    }

    private RoleAssignee findRoleAssignee(UnitOfWork uow, String username) {
        QueryBuilder<RoleAssignee> builder = module.newQueryBuilder(RoleAssignee.class);
        builder = builder.where(eq(templateFor(RoleAssignee.class).subjectIdentifier(), username));
        return uow.newQuery(builder).find();
    }

}