package io.vertx.ext.web.handler.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
import java.util.function.BiConsumer;
import io.vertx.core.impl.logging.Logger;
import io.vertx.core.impl.logging.LoggerFactory;
import io.vertx.ext.auth.authorization.Authorization;
import io.vertx.ext.auth.authorization.AuthorizationContext;
import io.vertx.ext.auth.authorization.AuthorizationProvider;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.AuthorizationHandler;
public class AuthorizationHandlerImpl implements AuthorizationHandler {
private final static Logger LOG = LoggerFactory.getLogger(AuthorizationHandler.class);
private final static int FORBIDDEN_CODE = 403;
private final static HttpStatusException FORBIDDEN_EXCEPTION = new HttpStatusException(FORBIDDEN_CODE);
private final Authorization authorization;
private final Collection<AuthorizationProvider> authorizationProviders;
private BiConsumer<RoutingContext, AuthorizationContext> variableHandler;
public AuthorizationHandlerImpl(Authorization authorization) {
this.authorization = Objects.requireNonNull(authorization);
this.authorizationProviders = new ArrayList<>();
}
@Override
public void handle(RoutingContext routingContext) {
if (routingContext.user() == null) {
routingContext.fail(FORBIDDEN_CODE, FORBIDDEN_EXCEPTION);
} else {
AuthorizationContext authorizationContext = getAuthorizationContext(routingContext);
checkOrFetchAuthorizations(routingContext, authorizationContext, authorizationProviders.iterator());
}
}
@Override
public AuthorizationHandler variableConsumer(BiConsumer<RoutingContext, AuthorizationContext> handler) {
this.variableHandler = handler;
return this;
}
private void checkOrFetchAuthorizations(RoutingContext routingContext, AuthorizationContext authorizationContext, Iterator<AuthorizationProvider> providers) {
if (authorization.match(authorizationContext)) {
routingContext.next();
return;
}
if (!providers.hasNext()) {
routingContext.fail(FORBIDDEN_CODE, FORBIDDEN_EXCEPTION);
return;
}
while (providers.hasNext()) {
AuthorizationProvider provider = providers.next();
if (! routingContext.user().authorizations().getProviderIds().contains(provider.getId())) {
provider.getAuthorizations(routingContext.user(), authorizationResult -> {
if (authorizationResult.failed()) {
LOG.warn("An error occured getting authorization - providerId: " + provider.getId(), authorizationResult.cause());
}
checkOrFetchAuthorizations(routingContext, authorizationContext, providers);
});
return;
}
}
}
private AuthorizationContext getAuthorizationContext(RoutingContext event) {
final AuthorizationContext result = AuthorizationContext.create(event.user());
if (variableHandler != null) {
variableHandler.accept(event, result);
}
return result;
}
@Override
public AuthorizationHandler addAuthorizationProvider(AuthorizationProvider authorizationProvider) {
Objects.requireNonNull(authorizationProvider);
this.authorizationProviders.add(authorizationProvider);
return this;
}
}