1 package org.onap.ccsdk.features.sdnr.wt.oauthprovider.filters;
 
   3 import com.google.common.collect.Iterables;
 
   4 import com.google.common.util.concurrent.Futures;
 
   5 import com.google.common.util.concurrent.ListenableFuture;
 
   6 import org.apache.shiro.subject.Subject;
 
   7 import org.apache.shiro.web.filter.authz.AuthorizationFilter;
 
   8 import org.opendaylight.mdsal.binding.api.*;
 
   9 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 
  10 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.HttpAuthorization;
 
  11 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.authorization.policies.Policies;
 
  12 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.permission.Permissions;
 
  13 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 
  14 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
  15 import org.slf4j.Logger;
 
  16 import org.slf4j.LoggerFactory;
 
  18 import javax.servlet.Filter;
 
  19 import javax.servlet.ServletRequest;
 
  20 import javax.servlet.ServletResponse;
 
  21 import javax.servlet.http.HttpServletRequest;
 
  22 import javax.servlet.http.HttpServletResponse;
 
  23 import java.io.IOException;
 
  25 import java.util.concurrent.ExecutionException;
 
  27 import static com.google.common.base.Preconditions.checkArgument;
 
  28 import static java.util.Objects.requireNonNull;
 
  30 public class CustomizedMDSALDynamicAuthorizationFilter extends AuthorizationFilter
 
  31         implements ClusteredDataTreeChangeListener<HttpAuthorization> {
 
  33     private static final Logger LOG = LoggerFactory.getLogger(CustomizedMDSALDynamicAuthorizationFilter.class);
 
  35     private static final DataTreeIdentifier<HttpAuthorization> AUTHZ_CONTAINER = DataTreeIdentifier.create(
 
  36             LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(HttpAuthorization.class));
 
  38     private final DataBroker dataBroker;
 
  40     private ListenerRegistration<?> reg;
 
  41     private volatile ListenableFuture<Optional<HttpAuthorization>> authContainer;
 
  42     private static final ThreadLocal<DataBroker> DATABROKER_TL = new ThreadLocal<>();
 
  44     public CustomizedMDSALDynamicAuthorizationFilter() {
 
  45         dataBroker = requireNonNull(DATABROKER_TL.get());
 
  49     public Filter processPathConfig(final String path, final String config) {
 
  50         try (ReadTransaction tx = dataBroker.newReadOnlyTransaction()) {
 
  51             authContainer = tx.read(AUTHZ_CONTAINER.getDatastoreType(), AUTHZ_CONTAINER.getRootIdentifier());
 
  53         this.reg = dataBroker.registerDataTreeChangeListener(AUTHZ_CONTAINER, this);
 
  54         return super.processPathConfig(path, config);
 
  58     public void destroy() {
 
  67     public void onDataTreeChanged(final Collection<DataTreeModification<HttpAuthorization>> changes) {
 
  68         final HttpAuthorization newVal = Iterables.getLast(changes).getRootNode().getDataAfter();
 
  69         LOG.debug("Updating authorization information to {}", newVal);
 
  70         authContainer = Futures.immediateFuture(Optional.ofNullable(newVal));
 
  74     public boolean isAccessAllowed(final ServletRequest request, final ServletResponse response,
 
  75                                    final Object mappedValue) {
 
  76         checkArgument(request instanceof HttpServletRequest, "Expected HttpServletRequest, received {}", request);
 
  79         final boolean defaultReturnValue=false;
 
  80         final Subject subject = getSubject(request, response);
 
  81         final HttpServletRequest httpServletRequest = (HttpServletRequest)request;
 
  82         final String requestURI = httpServletRequest.getRequestURI();
 
  83         LOG.debug("isAccessAllowed for user={} to requestURI={}", subject, requestURI);
 
  85         final Optional<HttpAuthorization> authorizationOptional;
 
  87             authorizationOptional = authContainer.get();
 
  88         } catch (ExecutionException | InterruptedException e) {
 
  89             // Something went completely wrong trying to read the authz container.  Deny access.
 
  90             LOG.warn("MDSAL attempt to read Http Authz Container failed, disallowing access", e);
 
  94         if (!authorizationOptional.isPresent()) {
 
  95             // The authorization container does not exist-- hence no authz rules are present
 
  97             LOG.debug("Authorization Container does not exist");
 
  98             return defaultReturnValue;
 
 101         final HttpAuthorization httpAuthorization = authorizationOptional.get();
 
 102         final var policies = httpAuthorization.getPolicies();
 
 103         List<Policies> policiesList = policies != null ? policies.getPolicies() : null;
 
 104         if (policiesList == null || policiesList.isEmpty()) {
 
 105             // The authorization container exists, but no rules are present.  Allow access.
 
 106             LOG.debug("Exiting early since no authorization rules exist");
 
 107             sendError(response, 403, "");
 
 108             return defaultReturnValue;
 
 111         // Sort the Policies list based on index
 
 112         policiesList = new ArrayList<>(policiesList);
 
 113         policiesList.sort(Comparator.comparing(Policies::getIndex));
 
 115         for (Policies policy : policiesList) {
 
 116             final String resource = policy.getResource();
 
 117             final boolean pathsMatch = pathsMatch(resource, requestURI);
 
 119                 LOG.debug("paths match for policy {} pattern={} and requestURI={}", policy.getIndex(), resource, requestURI);
 
 120                 final String method = httpServletRequest.getMethod();
 
 121                 LOG.trace("method={}", method);
 
 122                 List<Permissions> permissions = policy.getPermissions();
 
 123                 LOG.trace("perm={}", permissions);
 
 124                 if(permissions !=null) {
 
 125                     for (Permissions permission : permissions) {
 
 126                         final String role = permission.getRole();
 
 127                         LOG.trace("role={}", role);
 
 128                         Set<Permissions.Actions> actions = permission.getActions();
 
 129                         if (actions != null) {
 
 130                             for (Permissions.Actions action : actions) {
 
 131                                 LOG.trace("action={}", action.getName());
 
 132                                 if (action.getName().equalsIgnoreCase(method)) {
 
 133                                     final boolean hasRole = subject.hasRole(role);
 
 134                                     LOG.trace("hasRole({})={}", role, hasRole);
 
 142                             LOG.trace("no actions found");
 
 147                     LOG.trace("no permissions found");
 
 149                 LOG.debug("couldn't authorize the user for access");
 
 150                 sendError(response, 403, "");
 
 154         LOG.debug("no path found that matches {}", requestURI);
 
 155         sendError(response, 403, "");
 
 156         return defaultReturnValue;
 
 159     private void sendError(ServletResponse response, int code, String message)  {
 
 160         if(response instanceof HttpServletResponse){
 
 162                 ((HttpServletResponse)response).sendError(code, message);
 
 163             } catch (IOException e) {
 
 164                 LOG.warn("unable to send {} {} response: ", code, message, e);
 
 168             LOG.warn("unable to send {} {} response", code, message);