Merge "fix oauth code"
[ccsdk/features.git] / sdnr / wt / oauth-provider / oauth-core / src / main / java / org / onap / ccsdk / features / sdnr / wt / oauthprovider / http / AuthHttpServlet.java
@@ -22,6 +22,7 @@
 package org.onap.ccsdk.features.sdnr.wt.oauthprovider.http;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -43,26 +44,23 @@ import org.apache.shiro.authc.BearerToken;
 import org.apache.shiro.codec.Base64;
 import org.apache.shiro.session.Session;
 import org.apache.shiro.subject.Subject;
-import org.jolokia.osgi.security.Authenticator;
-import org.onap.ccsdk.features.sdnr.wt.common.http.BaseHTTPClient;
-import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
-import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.InvalidConfigurationException;
-import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.NoDefinitionFoundException;
-import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthProviderConfig;
-import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthToken;
-import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlPolicy;
-import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UnableToConfigureOAuthService;
-import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.*;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlShiroConfiguration.MainItem;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlShiroConfiguration.UrlItem;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.filters.CustomizedMDSALDynamicAuthorizationFilter;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.AuthService;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.AuthService.PublicOAuthProviderConfig;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.MdSalAuthorizationStore;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.OAuthProviderFactory;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
-import org.opendaylight.aaa.api.IdMService;
+import org.opendaylight.aaa.api.AuthenticationException;
+import org.opendaylight.aaa.api.Claim;
+import org.opendaylight.aaa.api.PasswordCredentialAuth;
+import org.opendaylight.aaa.api.PasswordCredentials;
+import org.opendaylight.aaa.tokenauthrealm.auth.PasswordCredentialBuilder;
 import org.opendaylight.mdsal.binding.api.DataBroker;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfiguration;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.shiro.ini.Main;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.shiro.ini.Urls;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -70,7 +68,7 @@ public class AuthHttpServlet extends HttpServlet {
 
     private static final Logger LOG = LoggerFactory.getLogger(AuthHttpServlet.class.getName());
     private static final long serialVersionUID = 1L;
-    public static final String BASEURI = "/oauth";
+    private static final String BASEURI = "/oauth";
     private static final String LOGINURI = BASEURI + "/login";
     private static final String LOGOUTURI = BASEURI + "/logout";
     private static final String PROVIDERSURI = BASEURI + "/providers";
@@ -93,20 +91,26 @@ public class AuthHttpServlet extends HttpServlet {
     private static final String CLASSNAME_ODLMDSALAUTH =
             "org.opendaylight.aaa.shiro.realm.MDSALDynamicAuthorizationFilter";
     public static final String LOGIN_REDIRECT_FORMAT = LOGINURI + "/%s";
+    private static final String URI_PRE = BASEURI;
 
+    private static final String CONFIGFILE ="/opt/opendaylight/etc/opendaylight/datastore/initial/config/aaa-app-config.xml";
     private final ObjectMapper mapper;
     /* state <=> AuthProviderService> */
     private final Map<String, AuthService> providerStore;
     private final TokenCreator tokenCreator;
     private final Config config;
-    private static Authenticator odlAuthenticator;
-    private static IdMService odlIdentityService;
-    private static ShiroConfiguration shiroConfiguration;
     private static MdSalAuthorizationStore mdsalAuthStore;
+    private PasswordCredentialAuth passwordCredentialAuth;
+    private OdlShiroConfiguration shiroConfiguration;
 
     public AuthHttpServlet() throws IllegalArgumentException, IOException, InvalidConfigurationException,
             UnableToConfigureOAuthService {
+        this(CONFIGFILE);
+    }
+    public AuthHttpServlet(String shiroconfigfile) throws IllegalArgumentException, IOException, InvalidConfigurationException,
+            UnableToConfigureOAuthService {
         this.config = Config.getInstance();
+        this.shiroConfiguration = loadShiroConfig(shiroconfigfile);
         this.tokenCreator = TokenCreator.getInstance(this.config);
         this.mapper = new ObjectMapper();
         this.providerStore = new HashMap<>();
@@ -116,20 +120,33 @@ public class AuthHttpServlet extends HttpServlet {
         }
     }
 
-    public void setOdlAuthenticator(Authenticator odlAuthenticator2) {
-        odlAuthenticator = odlAuthenticator2;
+    public void setDataBroker(DataBroker dataBroker) {
+        CustomizedMDSALDynamicAuthorizationFilter.setDataBroker(dataBroker);
+        mdsalAuthStore = new MdSalAuthorizationStore(dataBroker);
     }
 
-    public void setOdlIdentityService(IdMService odlIdentityService2) {
-        odlIdentityService = odlIdentityService2;
+    public void setPasswordCredentialAuth(PasswordCredentialAuth passwordCredentialAuth) {
+        this.passwordCredentialAuth = passwordCredentialAuth;
     }
 
-    public void setShiroConfiguration(ShiroConfiguration shiroConfiguration2) {
-        shiroConfiguration = shiroConfiguration2;
+
+    public void onUnbindService(HttpService httpService) {
+        httpService.unregister(AuthHttpServlet.URI_PRE);
+
     }
 
-    public void setDataBroker(DataBroker dataBroker) {
-        mdsalAuthStore = new MdSalAuthorizationStore(dataBroker);
+    public void onBindService(HttpService httpService)
+            throws ServletException, NamespaceException {
+        if (httpService == null) {
+            LOG.warn("Unable to inject HttpService into loader.");
+        } else {
+            httpService.registerServlet(AuthHttpServlet.URI_PRE, this, null, null);
+            LOG.info("oauth servlet registered.");
+        }
+    }
+    private static OdlShiroConfiguration loadShiroConfig(String filename) throws  IOException {
+        OdlXmlMapper mapper = new OdlXmlMapper();
+        return mapper.readValue(new File(filename), OdlShiroConfiguration.class);
     }
 
     @Override
@@ -158,10 +175,6 @@ public class AuthHttpServlet extends HttpServlet {
         if (redirectUrl == null) {
             redirectUrl = this.config.getPublicUrl();
         }
-        // if nothing configured and nothing from request
-        if(redirectUrl == null || redirectUrl.isBlank()){
-            redirectUrl="/";
-        }
         UserTokenPayload userInfo = this.tokenCreator.decode(bearerToken);
         if (bearerToken != null && userInfo != null && !userInfo.isInternal()) {
             AuthService provider = this.providerStore.getOrDefault(userInfo.getProviderId(), null);
@@ -194,27 +207,26 @@ public class AuthHttpServlet extends HttpServlet {
 
     /**
      * find out what urls can be accessed by user and which are forbidden
-     *
+     * <p>
      * urlEntries: "anon" -> any access allowed "authcXXX" -> no grouping rule -> any access for user allowed "authcXXX,
      * roles[abc] -> user needs to have role abc "authcXXX, roles["abc,def"] -> user needs to have roles abc AND def
      * "authcXXX, anyroles[abc] -> user needs to have role abc "authcXXX, anyroles["abc,def"] -> user needs to have
      * roles abc OR def
      *
-     *
      * @param req
      * @return
      */
     private List<OdlPolicy> getPoliciesForUser(HttpServletRequest req) {
-        List<Urls> urlRules = shiroConfiguration.getUrls();
-        UserTokenPayload data = this.getUserInfo(req);
         List<OdlPolicy> policies = new ArrayList<>();
+        List<UrlItem> urlRules = this.shiroConfiguration.getUrls();
+        UserTokenPayload data = this.getUserInfo(req);
         if (urlRules != null) {
             LOG.debug("try to find rules for user {} with roles {}",
                     data == null ? "null" : data.getPreferredUsername(), data == null ? "null" : data.getRoles());
             final String regex = "^([^,]+)[,]?[\\ ]?([anyroles]+)?(\\[\"?([a-zA-Z,]+)\"?\\])?";
             final Pattern pattern = Pattern.compile(regex);
             Matcher matcher;
-            for (Urls urlRule : urlRules) {
+            for (UrlItem urlRule : urlRules) {
                 matcher = pattern.matcher(urlRule.getPairValue());
                 if (matcher.find()) {
                     try {
@@ -223,7 +235,7 @@ public class AuthHttpServlet extends HttpServlet {
                         //anon access allowed
                         if (authClass == null) {
                             policy = Optional.of(OdlPolicy.allowAll(urlRule.getPairKey()));
-                        } else if (authClass.equals(CLASSNAME_ODLBASICAUTH)) {
+                        } else if (authClass.equals(CLASSNAME_ODLBASICAUTH) || "authcBasic".equals(urlRule.getPairKey())) {
                             policy = isBasic(req) ? this.getTokenBasedPolicy(urlRule, matcher, data)
                                     : Optional.of(OdlPolicy.denyAll(urlRule.getPairKey()));
                         } else if (authClass.equals(CLASSNAME_ODLBEARERANDBASICAUTH)) {
@@ -259,7 +271,7 @@ public class AuthHttpServlet extends HttpServlet {
      * @param data
      * @return
      */
-    private Optional<OdlPolicy> getMdSalBasedPolicy(Urls urlRule, UserTokenPayload data) {
+    private Optional<OdlPolicy> getMdSalBasedPolicy(UrlItem urlRule, UserTokenPayload data) {
         if (mdsalAuthStore != null) {
             return data != null ? mdsalAuthStore.getPolicy(urlRule.getPairKey(), data.getRoles())
                     : Optional.of(OdlPolicy.denyAll(urlRule.getPairKey()));
@@ -275,7 +287,8 @@ public class AuthHttpServlet extends HttpServlet {
      * @param data
      * @return
      */
-    private Optional<OdlPolicy> getTokenBasedPolicy(Urls urlRule, Matcher matcher, UserTokenPayload data) {
+    private Optional<OdlPolicy> getTokenBasedPolicy(UrlItem urlRule, Matcher matcher,
+                                                    UserTokenPayload data) {
         final String url = urlRule.getPairKey();
         final String rule = urlRule.getPairValue();
         if (!rule.contains(",")) {
@@ -312,8 +325,11 @@ public class AuthHttpServlet extends HttpServlet {
         if ("anon".equals(key)) {
             return null;
         }
-        List<Main> list = shiroConfiguration.getMain();
-        Optional<Main> main =
+        if("authcBasic".equals(key)){
+            return CLASSNAME_ODLBASICAUTH;
+        }
+        List<MainItem> list = shiroConfiguration.getMain();
+        Optional<MainItem> main =
                 list == null ? Optional.empty() : list.stream().filter(e -> e.getPairKey().equals(key)).findFirst();
         if (main.isPresent()) {
             return main.get().getPairValue();
@@ -334,7 +350,7 @@ public class AuthHttpServlet extends HttpServlet {
                 if (!username.contains("@")) {
                     username = String.format("%s@%s", username, domain);
                 }
-                List<String> roles = odlIdentityService.listRoles(username, domain);
+                List<String> roles = List.of();// odlIdentityService.listRoles(username, domain);
                 return UserTokenPayload.createInternal(username, roles);
             }
         }
@@ -361,12 +377,12 @@ public class AuthHttpServlet extends HttpServlet {
 
     private static boolean isBasic(HttpServletRequest req) {
         final String header = req.getHeader(HEAEDER_AUTHORIZATION);
-        return header == null ? false : header.startsWith("Basic");
+        return header != null && header.startsWith("Basic");
     }
 
     private static boolean isBearer(HttpServletRequest req) {
         final String header = req.getHeader(HEAEDER_AUTHORIZATION);
-        return header == null ? false : header.startsWith("Bearer");
+        return header != null && header.startsWith("Bearer");
     }
 
     private boolean rolesMatch(List<String> userRoles, List<String> policyRoles, boolean any) {
@@ -399,7 +415,7 @@ public class AuthHttpServlet extends HttpServlet {
                 hostUrl = matcher.group(1);
             }
         }
-        LOG.debug("host={}", hostUrl);
+        LOG.info("host={}", hostUrl);
         return hostUrl;
 
     }
@@ -451,17 +467,21 @@ public class AuthHttpServlet extends HttpServlet {
             }
 
         }
-        resp.sendError(HttpServletResponse.SC_NOT_FOUND);
+        resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
     }
 
     private BearerToken doLogin(String username, String password, String domain) {
-        if (!username.contains("@")) {
-            username = String.format("%s@%s", username, domain);
+
+        PasswordCredentials pc =
+                (new PasswordCredentialBuilder()).setUserName(username).setPassword(password).setDomain(domain).build();
+        Claim claim = null;
+        try {
+            claim = this.passwordCredentialAuth.authenticate(pc);
+        } catch (AuthenticationException e) {
+            LOG.warn("unable to authentication user {} for domain {}: ", username, domain, e);
         }
-        HttpServletRequest req = new HeadersOnlyHttpServletRequest(
-                Map.of("Authorization", BaseHTTPClient.getAuthorizationHeaderValue(username, password)));
-        if (odlAuthenticator.authenticate(req)) {
-            List<String> roles = odlIdentityService.listRoles(username, domain);
+        if (claim != null) {
+            List<String> roles = claim.roles().stream().toList();//odlIdentityService.listRoles(username, domain);
             UserTokenPayload data = new UserTokenPayload();
             data.setPreferredUsername(username);
             data.setFamilyName("");
@@ -470,15 +490,16 @@ public class AuthHttpServlet extends HttpServlet {
             data.setExp(this.tokenCreator.getDefaultExp());
             data.setRoles(roles);
             return this.tokenCreator.createNewJWT(data);
-
+        } else {
+            LOG.info("unable to read auth from authservice");
         }
         return null;
     }
 
 
-    private void sendResponse(HttpServletResponse resp, int code) throws IOException {
+/*    private void sendResponse(HttpServletResponse resp, int code) throws IOException {
         this.sendResponse(resp, code, null);
-    }
+    }*/
 
     private void sendResponse(HttpServletResponse resp, int code, Object data) throws IOException {
         byte[] output = data != null ? mapper.writeValueAsString(data).getBytes() : new byte[0];
@@ -486,14 +507,13 @@ public class AuthHttpServlet extends HttpServlet {
         resp.setStatus(code);
         resp.setContentLength(output.length);
         resp.setContentType("application/json");
-        ServletOutputStream os = null;
-        os = resp.getOutputStream();
+        ServletOutputStream os = resp.getOutputStream();
         os.write(output);
 
     }
 
     private void logout() {
-        final Subject subject = SecurityUtils.getSubject();
+       /* final Subject subject = SecurityUtils.getSubject();
         try {
             subject.logout();
             Session session = subject.getSession(false);
@@ -502,6 +522,6 @@ public class AuthHttpServlet extends HttpServlet {
             }
         } catch (ShiroException e) {
             LOG.debug("Couldn't log out {}", subject, e);
-        }
+        }*/
     }
 }