80d9d1bb64749ee754658236e1320943b74ee8c7
[ccsdk/features.git] /
1 package org.onap.ccsdk.features.sdnr.wt.oauthprovider.filters;
2
3 import static com.google.common.base.Preconditions.checkArgument;
4 import static java.util.Objects.requireNonNull;
5
6 import com.google.common.collect.Iterables;
7 import com.google.common.util.concurrent.Futures;
8 import com.google.common.util.concurrent.ListenableFuture;
9
10 import java.util.*;
11 import java.util.concurrent.ExecutionException;
12 import javax.servlet.Filter;
13 import javax.servlet.ServletRequest;
14 import javax.servlet.ServletResponse;
15 import javax.servlet.http.HttpServletRequest;
16 import org.apache.shiro.subject.Subject;
17 import org.apache.shiro.web.filter.authz.AuthorizationFilter;
18 import org.opendaylight.aaa.shiro.web.env.ThreadLocals;
19 import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
20 import org.opendaylight.mdsal.binding.api.DataBroker;
21 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
22 import org.opendaylight.mdsal.binding.api.DataTreeModification;
23 import org.opendaylight.mdsal.binding.api.ReadTransaction;
24 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.HttpAuthorization;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.authorization.policies.Policies;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.permission.Permissions;
28 import org.opendaylight.yangtools.concepts.ListenerRegistration;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 @SuppressWarnings("checkstyle:AbbreviationAsWordInName")
34 public class CustomizedMDSALDynamicAuthorizationFilter extends AuthorizationFilter
35         implements ClusteredDataTreeChangeListener<HttpAuthorization> {
36
37     private static final Logger LOG = LoggerFactory.getLogger(CustomizedMDSALDynamicAuthorizationFilter.class);
38
39     private static final DataTreeIdentifier<HttpAuthorization> AUTHZ_CONTAINER = DataTreeIdentifier.create(
40             LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(HttpAuthorization.class));
41
42     private final DataBroker dataBroker;
43
44     private ListenerRegistration<?> reg;
45     private volatile ListenableFuture<Optional<HttpAuthorization>> authContainer;
46
47     public CustomizedMDSALDynamicAuthorizationFilter() {
48         dataBroker = requireNonNull(ThreadLocals.DATABROKER_TL.get());
49     }
50
51     @Override
52     public Filter processPathConfig(final String path, final String config) {
53         try (ReadTransaction tx = dataBroker.newReadOnlyTransaction()) {
54             authContainer = tx.read(AUTHZ_CONTAINER.getDatastoreType(), AUTHZ_CONTAINER.getRootIdentifier());
55         }
56         this.reg = dataBroker.registerDataTreeChangeListener(AUTHZ_CONTAINER, this);
57         return super.processPathConfig(path, config);
58     }
59
60     @Override
61     public void destroy() {
62         if (reg != null) {
63             reg.close();
64             reg = null;
65         }
66         super.destroy();
67     }
68
69     @Override
70     public void onDataTreeChanged(final Collection<DataTreeModification<HttpAuthorization>> changes) {
71         final HttpAuthorization newVal = Iterables.getLast(changes).getRootNode().getDataAfter();
72         LOG.debug("Updating authorization information to {}", newVal);
73         authContainer = Futures.immediateFuture(Optional.ofNullable(newVal));
74     }
75
76     @Override
77     public boolean isAccessAllowed(final ServletRequest request, final ServletResponse response,
78                                    final Object mappedValue) {
79         checkArgument(request instanceof HttpServletRequest, "Expected HttpServletRequest, received {}", request);
80
81         final Subject subject = getSubject(request, response);
82         final HttpServletRequest httpServletRequest = (HttpServletRequest)request;
83         final String requestURI = httpServletRequest.getRequestURI();
84         LOG.debug("isAccessAllowed for user={} to requestURI={}", subject, requestURI);
85
86         final Optional<HttpAuthorization> authorizationOptional;
87         try {
88             authorizationOptional = authContainer.get();
89         } catch (ExecutionException | InterruptedException e) {
90             // Something went completely wrong trying to read the authz container.  Deny access.
91             LOG.warn("MDSAL attempt to read Http Authz Container failed, disallowing access", e);
92             return false;
93         }
94
95         if (!authorizationOptional.isPresent()) {
96             // The authorization container does not exist-- hence no authz rules are present
97             // Allow access.
98             LOG.debug("Authorization Container does not exist");
99             return true;
100         }
101
102         final HttpAuthorization httpAuthorization = authorizationOptional.get();
103         final var policies = httpAuthorization.getPolicies();
104         List<Policies> policiesList = policies != null ? policies.getPolicies() : null;
105         if (policiesList == null || policiesList.isEmpty()) {
106             // The authorization container exists, but no rules are present.  Allow access.
107             LOG.debug("Exiting successfully early since no authorization rules exist");
108             return true;
109         }
110
111         // Sort the Policies list based on index
112         policiesList = new ArrayList<>(policiesList);
113         policiesList.sort(Comparator.comparing(Policies::getIndex));
114
115         for (Policies policy : policiesList) {
116             final String resource = policy.getResource();
117             final boolean pathsMatch = pathsMatch(resource, requestURI);
118             if (pathsMatch) {
119                 LOG.debug("paths match for pattern={} and requestURI={}", resource, requestURI);
120                 final String method = httpServletRequest.getMethod();
121                 LOG.trace("method={}", method);
122                 List<Permissions> permissions = policy.getPermissions();
123                 if(permissions !=null) {
124                     for (Permissions permission : permissions) {
125                         final String role = permission.getRole();
126                         LOG.trace("role={}", role);
127                         Set<Permissions.Actions> actions = permission.getActions();
128                         if (actions != null) {
129                             for (Permissions.Actions action : actions) {
130                                 LOG.trace("action={}", action.getName());
131                                 if (action.getName().equalsIgnoreCase(method)) {
132                                     final boolean hasRole = subject.hasRole(role);
133                                     LOG.trace("hasRole({})={}", role, hasRole);
134                                     if (hasRole) {
135                                         return true;
136                                     }
137                                 }
138                             }
139                         }
140                         else{
141                             LOG.trace("no actions found");
142                         }
143                     }
144                 }
145                 else {
146                     LOG.trace("no permissions found");
147                 }
148                 LOG.debug("couldn't authorize the user for access");
149                 return false;
150             }
151         }
152         LOG.debug("successfully authorized the user for access");
153         return true;
154     }
155 }