From 6c1d717147400ebda2b6e8713bbbb6c309702aa7 Mon Sep 17 00:00:00 2001 From: Instrumental Date: Fri, 9 Nov 2018 17:50:40 -0600 Subject: CADI Enforcement Point Issue-ID: AAF-623 Change-Id: Ib49b68fe8323af895b80a90537e7d1c75bc46b70 Signed-off-by: Instrumental --- .../org/onap/aaf/auth/validation/Validator.java | 2 +- .../main/java/org/onap/aaf/cadi/aaf/PermEval.java | 2 +- .../java/org/onap/aaf/cadi/aaf/v2_0/AAFTaf.java | 3 +- .../org/onap/aaf/cadi/aaf/test/JU_PermEval.java | 2 + .../main/java/org/onap/aaf/cadi/config/Config.java | 5 +- .../aaf/cadi/filter/CadiApiEnforcementFilter.java | 132 +++++++++++++++++++++ .../java/org/onap/aaf/cadi/filter/CadiFilter.java | 27 ++--- .../java/org/onap/aaf/cadi/filter/SideChain.java | 73 ++++++++++++ 8 files changed, 225 insertions(+), 21 deletions(-) create mode 100644 cadi/core/src/main/java/org/onap/aaf/cadi/filter/CadiApiEnforcementFilter.java create mode 100644 cadi/core/src/main/java/org/onap/aaf/cadi/filter/SideChain.java diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/validation/Validator.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/validation/Validator.java index 1c9f4123..7e861eda 100644 --- a/auth/auth-core/src/main/java/org/onap/aaf/auth/validation/Validator.java +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/validation/Validator.java @@ -155,7 +155,7 @@ public class Validator { } public final Validator permInstance(String instance) { - if (nob(instance,instChars)) { + if(!"/".equals(instance) && nob(instance,instChars)) { msg("Perm Instance [" + instance + "] is invalid."); } return this; diff --git a/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/PermEval.java b/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/PermEval.java index c12b2e6d..2c7aa12b 100644 --- a/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/PermEval.java +++ b/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/PermEval.java @@ -77,7 +77,7 @@ public class PermEval { if (pass=sItem.length()==0) { break; // Both Empty, keep checking } - } else if (sItem.charAt(0)==START_REGEX_CHAR) { // Check Server side when wildcarding like * + } else if (sItem.length()>0 && sItem.charAt(0)==START_REGEX_CHAR) { // Check Server side when wildcarding like * if (pass=pkeys[i].matches(sItem.substring(1))) { break; // Matches, keep checking } diff --git a/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AAFTaf.java b/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AAFTaf.java index c27dd123..ea404400 100644 --- a/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AAFTaf.java +++ b/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AAFTaf.java @@ -93,8 +93,9 @@ public class AAFTaf extends AbsUserCache implements HttpT } else { try { mapIds = new MapBathConverter(access, new CSV(csvFile)); + access.log(Level.INIT,"Basic Auth Conversion using",csvFile,"enabled" ); } catch (IOException | CadiException e) { - access.log(e,"Bath Map Conversion is not initialzed (non fatal)"); + access.log(e,"Bath Map Conversion is not initialized (non fatal)"); } } diff --git a/cadi/aaf/src/test/java/org/onap/aaf/cadi/aaf/test/JU_PermEval.java b/cadi/aaf/src/test/java/org/onap/aaf/cadi/aaf/test/JU_PermEval.java index a6c0f916..3e137c25 100644 --- a/cadi/aaf/src/test/java/org/onap/aaf/cadi/aaf/test/JU_PermEval.java +++ b/cadi/aaf/src/test/java/org/onap/aaf/cadi/aaf/test/JU_PermEval.java @@ -74,6 +74,8 @@ public class JU_PermEval { // Accept matching empty keys assertThat(PermEval.evalInstance(":", ":"), is(true)); + assertThat(PermEval.evalInstance("/", "/"), is(true)); + assertThat(PermEval.evalInstance("/something/", "/something/"), is(true)); // Reject non-matching empty keys assertThat(PermEval.evalInstance(":fred", ":"), is(false)); diff --git a/cadi/core/src/main/java/org/onap/aaf/cadi/config/Config.java b/cadi/core/src/main/java/org/onap/aaf/cadi/config/Config.java index 3d668c42..0e4f72b8 100644 --- a/cadi/core/src/main/java/org/onap/aaf/cadi/config/Config.java +++ b/cadi/core/src/main/java/org/onap/aaf/cadi/config/Config.java @@ -103,7 +103,10 @@ public class Config { public static final String CADI_PROTOCOLS = "cadi_protocols"; public static final String CADI_NOAUTHN = "cadi_noauthn"; public static final String CADI_LOC_LIST = "cadi_loc_list"; + + // Special Behaviors public static final String CADI_BATH_CONVERT = "cadi_bath_convert"; + public static final String CADI_API_ENFORCEMENT = "cadi_api_enforcement"; public static final String CADI_USER_CHAIN_TAG = "cadi_user_chain"; public static final String CADI_USER_CHAIN = "USER_CHAIN"; @@ -410,7 +413,7 @@ public class Config { oadtClss = Class.forName(OAUTH_DIRECT_TAF); } catch (ClassNotFoundException e1) { oadtClss = null; - access.log(Level.INIT, e1); + access.log(Level.DEBUG, e1); } if (additionalTafLurs!=null && additionalTafLurs.length>0 && (oadtClss!=null && additionalTafLurs[0].getClass().isAssignableFrom(oadtClss))) { htlist.add((HttpTaf)additionalTafLurs[0]); diff --git a/cadi/core/src/main/java/org/onap/aaf/cadi/filter/CadiApiEnforcementFilter.java b/cadi/core/src/main/java/org/onap/aaf/cadi/filter/CadiApiEnforcementFilter.java new file mode 100644 index 00000000..495131b9 --- /dev/null +++ b/cadi/core/src/main/java/org/onap/aaf/cadi/filter/CadiApiEnforcementFilter.java @@ -0,0 +1,132 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + */ +package org.onap.aaf.cadi.filter; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.ServletContextAccess; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.util.Split; + +/** + * This filter allows one to protect the APIs from data stored in AAF + * + * @author Instrumental(Jonathan) + */ +public class CadiApiEnforcementFilter implements Filter { + private String type; + private Map> publicPaths; + private Access access; + + + public CadiApiEnforcementFilter(Access access, String enforce) throws ServletException { + this.access = access; + init(enforce); + } + + + @Override + public void init(FilterConfig fc) throws ServletException { + init(fc.getInitParameter(Config.CADI_API_ENFORCEMENT)); + // need the Context for Logging, instantiating ClassLoader, etc + ServletContextAccess sca=new ServletContextAccess(fc); + if (access==null) { + access = sca; + } + } + + private void init(final String ptypes) throws ServletException { + if(ptypes==null) { + throw new ServletException("CadiApiEnforcement requires " + Config.CADI_API_ENFORCEMENT + " property"); + } + String[] full = Split.splitTrim(';', ptypes); + if(full.length==0) { + throw new ServletException(Config.CADI_API_ENFORCEMENT + " property is empty"); + } + if(full.length>0) { + type=full[0]; + } + publicPaths = new TreeMap>(); + if(full.length>1) { + for(int i=1;i ls = publicPaths.get(pubArray[0]); + if(ls==null) { + ls = new ArrayList(); + publicPaths.put(pubArray[0], ls); + } + ls.add(pubArray[1]); + } + } + } + } + + + @Override + public void doFilter(ServletRequest req, ServletResponse resp, FilterChain fc) throws IOException, ServletException { + HttpServletRequest hreq = (HttpServletRequest)req; + final String meth = hreq.getMethod(); + final String path = hreq.getContextPath()+hreq.getPathInfo(); + List list = publicPaths.get(meth); + if(list!=null) { + for( String p : publicPaths.get(meth)) { + if(path.startsWith(p)) { + access.printf(Level.INFO, "%s accessed public API %s %s\n", + hreq.getUserPrincipal().getName(), + meth, + path); + fc.doFilter(req, resp); + return; + } + } + } + if(hreq.isUserInRole(type + '|'+path+'|'+meth)) { + access.printf(Level.INFO, "%s is allowed access to %s %s\n", + hreq.getUserPrincipal().getName(), + meth, + path); + fc.doFilter(req, resp); + } else { + access.printf(Level.AUDIT, "%s is denied access to %s %s\n", + hreq.getUserPrincipal().getName(), + meth, + path); + } + } + + @Override + public void destroy() { + } +} diff --git a/cadi/core/src/main/java/org/onap/aaf/cadi/filter/CadiFilter.java b/cadi/core/src/main/java/org/onap/aaf/cadi/filter/CadiFilter.java index cd48556b..2305eacd 100644 --- a/cadi/core/src/main/java/org/onap/aaf/cadi/filter/CadiFilter.java +++ b/cadi/core/src/main/java/org/onap/aaf/cadi/filter/CadiFilter.java @@ -71,7 +71,7 @@ public class CadiFilter implements Filter { private static List mapPairs; private Access access; private Object[] additionalTafLurs; - private Filter oauthFilter; + private SideChain sideChain; private static int count=0; public Lur getLur() { @@ -140,6 +140,7 @@ public class CadiFilter implements Filter { @SuppressWarnings("unchecked") private void init(Get getter) throws ServletException { + sideChain = new SideChain(); // Start with the assumption of "Don't trust anyone". TrustChecker tc = TrustChecker.NOTRUST; // default position try { @@ -158,22 +159,9 @@ public class CadiFilter implements Filter { Class cf=null; try { cf= (Class) Class.forName("org.onap.aaf.cadi.oauth.OAuthFilter"); - oauthFilter = cf.newInstance(); + sideChain.add(cf.newInstance()); } catch (ClassNotFoundException e) { - oauthFilter = new Filter() { // Null Filter - @Override - public void destroy() { - } - - @Override - public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)throws IOException, ServletException { - chain.doFilter(req, resp); - } - - @Override - public void init(FilterConfig arg0) throws ServletException { - } - }; + access.log(Level.DEBUG, "OAuthFilter not enabled"); } } catch (Exception e) { access.log(Level.INIT, "AAFTrustChecker cannot be loaded",e.getMessage()); @@ -238,6 +226,11 @@ public class CadiFilter implements Filter { } } + // Add API Enforcement Point + String enforce = getter.get(Config.CADI_API_ENFORCEMENT, null, true); + if(enforce!=null && enforce.length()>0) { + sideChain.add(new CadiApiEnforcementFilter(access,enforce)); + } // Remove Getter getter = Get.NULL; } @@ -287,7 +280,7 @@ public class CadiFilter implements Filter { CadiWrap cw = new CadiWrap(hreq, tresp, httpChecker.getLur(),getConverter(hreq)); if (httpChecker.notCadi(cw, hresp)) { startCode=System.nanoTime(); - oauthFilter.doFilter(cw,response,chain); + sideChain.doFilter(cw,response,chain); code = Timing.millis(startCode); } } diff --git a/cadi/core/src/main/java/org/onap/aaf/cadi/filter/SideChain.java b/cadi/core/src/main/java/org/onap/aaf/cadi/filter/SideChain.java new file mode 100644 index 00000000..8283b4dd --- /dev/null +++ b/cadi/core/src/main/java/org/onap/aaf/cadi/filter/SideChain.java @@ -0,0 +1,73 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + */ + +package org.onap.aaf.cadi.filter; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.xml.ws.Holder; + +/** + * Add various Filters by CADI Property not in the official Chain + * + * @author Instrumental(Jonathan) + * + */ +public class SideChain { + private List sideChain; + + public SideChain() { + sideChain = new ArrayList(); + } + + public void add(Filter f) { + sideChain.add(f); + } + + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException { + final Holder hbool = new Holder(Boolean.TRUE); + FilterChain truth = new FilterChain() { + @Override + public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { + hbool.value=Boolean.TRUE; + } + public String toString() { + return hbool.value.toString(); + } + }; + for(Filter f : sideChain) { + hbool.value=Boolean.FALSE; + f.doFilter(request, response, truth); + if(!hbool.value) { + return; + } + } + if(hbool.value) { + chain.doFilter(request, response); + } + } +} -- cgit 1.2.3-korg