/*
 * Copyright 2014 Red Hat, Inc.
 *
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  and Apache License v2.0 which accompanies this distribution.
 *
 *  The Eclipse Public License is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *
 *  The Apache License v2.0 is available at
 *  http://www.opensource.org/licenses/apache2.0.php
 *
 *  You may elect to redistribute this code under either of these licenses.
 */

package io.vertx.ext.auth.shiro.impl;

import java.util.Objects;

import io.vertx.core.Future;
import io.vertx.ext.auth.authentication.CredentialValidationException;
import io.vertx.ext.auth.authentication.Credentials;
import io.vertx.ext.auth.authentication.UsernamePasswordCredentials;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.GetAuthorizationsHack;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.SubjectContext;
import org.apache.shiro.subject.support.DefaultSubjectContext;

import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.auth.User;
import io.vertx.ext.auth.impl.UserImpl;
import io.vertx.ext.auth.shiro.ShiroAuth;
import io.vertx.ext.auth.shiro.ShiroAuthOptions;

Author:Tim Fox
/** * * @author <a href="http://tfox.org">Tim Fox</a> */
public class ShiroAuthProviderImpl implements ShiroAuth { private Vertx vertx; private org.apache.shiro.mgt.SecurityManager securityManager; private String realmName; public static ShiroAuth create(Vertx vertx, ShiroAuthOptions options) { Realm realm; switch (options.getType()) { case PROPERTIES: realm = PropertiesAuthProvider.createRealm(options.getConfig()); break; case LDAP: realm = LDAPAuthProvider.createRealm(options.getConfig()); break; default: throw new IllegalArgumentException("Invalid shiro auth realm type: " + options.getType()); } return new ShiroAuthProviderImpl(vertx, realm); } public ShiroAuthProviderImpl(Vertx vertx, Realm realm) { this.vertx = vertx; this.securityManager = new DefaultSecurityManager(realm); this.realmName = realm.getName(); } @Override public void authenticate(JsonObject authInfo, Handler<AsyncResult<User>> resultHandler) { authenticate(new UsernamePasswordCredentials(authInfo), resultHandler); } @Override public void authenticate(Credentials credentials, Handler<AsyncResult<User>> resultHandler) { try { UsernamePasswordCredentials authInfo = (UsernamePasswordCredentials) credentials; authInfo.checkValid(null); vertx.executeBlocking(fut -> { // before doing any shiro operations set the context SecurityUtils.setSecurityManager(securityManager); // proceed SubjectContext subjectContext = new DefaultSubjectContext(); Subject subject = securityManager.createSubject(subjectContext); String username = authInfo.getUsername(); String password = authInfo.getPassword(); AuthenticationToken token = new UsernamePasswordToken(username, password); try { subject.login(token); fut.complete(createUser(securityManager, subject)); } catch (AuthenticationException e) { fut.fail(e); } }, resultHandler); } catch (ClassCastException | CredentialValidationException e) { resultHandler.handle(Future.failedFuture(e)); } } Vertx getVertx() { return vertx; } org.apache.shiro.mgt.SecurityManager getSecurityManager() { return securityManager; } String getRealmName() { return realmName; } private User createUser(org.apache.shiro.mgt.SecurityManager securityManager, Subject subject) { Objects.requireNonNull(securityManager); Objects.requireNonNull(subject); JsonObject principal = new JsonObject().put("username", subject.getPrincipal().toString()); User result = new UserImpl(principal); result.authorizations().add("shiro-authentication", GetAuthorizationsHack.getAuthorizations(securityManager, subject)); return result; } }