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;
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 -> {
SecurityUtils.setSecurityManager(securityManager);
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;
}
}