/*
 * oxTrust is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
 *
 * Copyright (c) 2017, Gluu
 */
package org.gluu.oxtrust.service.filter;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.Priority;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

import org.gluu.oxtrust.auth.uma.BaseUmaProtectionService;
import org.gluu.oxtrust.auth.uma.BindingUrls;
import org.jboss.weld.inject.WeldInstance;
import org.slf4j.Logger;

/**
 * A RestEasy filter to centralize protection of APIs with UMA based on path
 * pattern. Created by jgomer on 2017-11-25.
 * 
 * @author Yuriy Movchan Date: 02/14/2017
 */
// To protect methods with this filter just add the @ProtectedApi annotation to
// them and ensure there is a proper subclass
// of {@link BaseUmaProtectionService} that can handle specific protection logic
// for your particular case
@Provider
@ProtectedApi
@Priority(Priorities.AUTHENTICATION)
@RequestScoped
public class AuthorizationProcessingFilter implements ContainerRequestFilter {

	@Inject
	private Logger log;

	@Context
	private HttpHeaders httpHeaders;

	@Context
	private ResourceInfo resourceInfo;

	@Inject
	private WeldInstance<BaseUmaProtectionService> protectionServiceInstance;

	private Map<String, Class<BaseUmaProtectionService>> protectionMapping;

	/**
	 * This method performs the protection check of service invocations: it provokes
	 * returning an early error response if the underlying protection logic does not
	 * succeed, otherwise, makes the request flow to its destination service object
	 * 
	 * @param requestContext
	 *            The ContainerRequestContext associated to filter execution
	 * @throws IOException
	 *             In practice no exception is thrown here. It's present to conform
	 *             to interface implemented.
	 */
	@Override
	public void filter(ContainerRequestContext requestContext) throws IOException {
		String path = requestContext.getUriInfo().getPath();
		log.info("REST call to '{}' intercepted", path);
		BaseUmaProtectionService protectionService = null;
		for (String prefix : protectionMapping.keySet()) {
			if (path.startsWith(prefix)) {
				protectionService = protectionServiceInstance.select(protectionMapping.get(prefix)).get();
				break;
			}
		}
		if (protectionService == null) {
			log.warn(
					"No concrete UMA protection mechanism is associated to this path (resource will be accessed anonymously)");

		} else {
			log.info("Path is protected, proceeding with authorization processing...");
			Response authorizationResponse = protectionService.processAuthorization(httpHeaders, resourceInfo);
			if (authorizationResponse == null)
				log.info("Authorization passed"); // If authorization passed, proceed with actual processing of request
			else
				requestContext.abortWith(authorizationResponse);
		}

	}

	/**
	 * Builds a map around url patterns and service beans that are aimed to perform
	 * actual protection
	 */
	@SuppressWarnings("unchecked")
	@PostConstruct
	private void init() {
		protectionMapping = new HashMap<String, Class<BaseUmaProtectionService>>();
		for (WeldInstance.Handler<BaseUmaProtectionService> handler : protectionServiceInstance.handlers()) {
			Class<BaseUmaProtectionService> beanClass = (Class<BaseUmaProtectionService>) handler.getBean()
					.getBeanClass();
			BindingUrls annotation = beanClass.getAnnotation(BindingUrls.class);
			if (annotation != null) {
				for (String pattern : annotation.value()) {
					if (pattern.length() > 0) {
						protectionMapping.put(pattern, beanClass);
					}
				}
			}
		}
	}

}

@@ -209,16 +209,56 @@
 eption;%0A
+import java.lang.annotation.Annotation;%0A
 import j
@@ -296,16 +296,38 @@
 til.Map;
+%0Aimport java.util.Set;
 %0A%0Aimport
@@ -440,16 +440,182 @@
 Scoped;%0A
+import javax.enterprise.inject.Any;%0Aimport javax.enterprise.inject.Instance;%0Aimport javax.enterprise.inject.spi.Bean;%0Aimport javax.enterprise.inject.spi.BeanManager;%0A
 import j
@@ -1062,51 +1062,8 @@
 ls;%0A
-import org.jboss.weld.inject.WeldInstance;%0A
 impo
@@ -1792,20 +1792,16 @@
 private 
-Weld
 Instance
@@ -1853,16 +1853,61 @@
 nstance;
+%0A%09%0A%09@Inject%0A%09private BeanManager beanManager;
 %0A%0A%09priva
@@ -3773,214 +3773,161 @@
 ;%0A%09%09
-for (WeldInstance.Handler%3CBaseUmaProtectionService%3E handler : protectionServiceInstance.handlers()) %7B%0A%09%09%09Class%3CBaseUmaProtectionService%3E beanClass = (Class%3CBaseUmaProtectionService%3E) handler.getBean()%0A%09%09%09%09%09
+Set%3CBean%3C?%3E%3E beans = beanManager.getBeans(BaseUmaProtectionService.class, Any.Literal.INSTANCE);%0A%09%09%0A%09%09for (Bean bean : beans) %7B%0A%09%09%09Class beanClass = bean
 .get
@@ -3946,21 +3946,24 @@
 %0A%09%09%09
-BindingUrls a
+Annotation beanA
 nnot
@@ -4021,17 +4021,21 @@
 %0A%09%09%09if (
-a
+beanA
 nnotatio
@@ -4073,17 +4073,36 @@
 ttern : 
-a
+((BindingUrls) beanA
 nnotatio
@@ -4102,16 +4102,17 @@
 notation
+)
 .value()

Use BeanManager instead of WeldInstance to get UMA protected endpoints