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