From 85ab5ab820969f43b0463ef5a6b9f9aa0c3833e8 Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 Date: Tue, 11 Nov 2025 17:38:42 +0530 Subject: [PATCH 01/20] feat(DecoupleOauthResource): Code changes to decouple oauth resource connection --- .../config/ServerConfigurationResource.java | 4 + .../web/services/local/ResourceUtility.java | 1 + .../web/services/local/UserResource.java | 591 +++++++++++++----- 3 files changed, 444 insertions(+), 152 deletions(-) diff --git a/src/prerna/semoss/web/services/config/ServerConfigurationResource.java b/src/prerna/semoss/web/services/config/ServerConfigurationResource.java index 2e82999ed..4d950392c 100644 --- a/src/prerna/semoss/web/services/config/ServerConfigurationResource.java +++ b/src/prerna/semoss/web/services/config/ServerConfigurationResource.java @@ -222,8 +222,12 @@ private static Map getConfiguration(@Context HttpServletRequest // append values that can change without restarting the server // logins allowed myConfiguration.put("loginsAllowed", SocialPropertiesUtil.getInstance().getLoginsAllowed()); + // connections allowed + myConfiguration.put("connectionsAllowed", SocialPropertiesUtil.getInstance().getConnectionsAllowed()); // get a list of all the logins and the display name and if it is oauth myConfiguration.put("availableProviders", SocialPropertiesUtil.getInstance().getAvailableProviders()); + // get a list of all the resource providers and the display name if it is oauth + myConfiguration.put("availableResourceProviders", SocialPropertiesUtil.getInstance().getAvailableResourceProviders()); // is native registration allowed myConfiguration.put("nativeRegistration", SocialPropertiesUtil.getInstance().isNativeRegistrationAllowed()); diff --git a/src/prerna/semoss/web/services/local/ResourceUtility.java b/src/prerna/semoss/web/services/local/ResourceUtility.java index a7111cd94..5244d5783 100644 --- a/src/prerna/semoss/web/services/local/ResourceUtility.java +++ b/src/prerna/semoss/web/services/local/ResourceUtility.java @@ -36,6 +36,7 @@ public class ResourceUtility { allowAccessWithoutLogin.add("config/fetchCsrf"); allowAccessWithoutLogin.add("auth/logins"); allowAccessWithoutLogin.add("auth/loginsAllowed"); + allowAccessWithoutLogin.add("auth/connectionsAllowed"); allowAccessWithoutLogin.add("auth/login"); allowAccessWithoutLogin.add("auth/loginLDAP"); allowAccessWithoutLogin.add("auth/changeADPassword"); diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index 150ce803c..e39515d8d 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -141,10 +141,32 @@ public Response getAllLogins(@Context HttpServletRequest request) { session.invalidate(); } } - Map retMap = User.getLoginNames(semossUser); return WebUtility.getResponse(retMap, 200, newCookies.toArray(new NewCookie[] {})); } + + @GET + @Path("/connections") + public Response getAllConnections(@Context HttpServletRequest request) { + List newCookies = new ArrayList<>(); + HttpSession session = request.getSession(false); + User semossUser = null; + if (session != null) { + semossUser = (User) session.getAttribute(Constants.SESSION_USER); + } + + if (semossUser == null) { + // not authenticated + // remove any cookies we shouldn't have + WebUtility.expireSessionCookies(request, newCookies); + + if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { + session.invalidate(); + } + } + Map retMap = User.getConnectionsNames(semossUser); + return WebUtility.getResponse(retMap, 200, newCookies.toArray(new NewCookie[] {})); + } @GET @Produces("application/json") @@ -199,6 +221,9 @@ public Response logout(@PathParam("provider") String provider, } } + // drop all the resource token for the user + thisUser.dropAllResourceAccessToken(); + List nullCookies = null; if (noUser) { // when we call session.invalidate() the UserSessionLoader will properly log is @@ -309,6 +334,27 @@ public static void addAccessToken(AccessToken token, HttpServletRequest request, } } } + + /** + * Method to add an resource access token to a user + * + * @param token + * @param request + */ + public static void addResourceAccessToken(AccessToken token, HttpServletRequest request, boolean autoAdd) { + HttpSession session = request.getSession(); + User semossUser = (User) session.getAttribute(Constants.SESSION_USER); + if (autoAdd) { + SecurityUpdateUtils.addOAuthUser(token); + } + semossUser.setResourceAccessToken(token); + semossUser.setAnonymous(false); + session.setAttribute(Constants.SESSION_USER, semossUser); + + // log the user resource connection + classLogger.info("User is connected to provider " + token.getProvider()); + + } public static void userTrackingLogin(HttpServletRequest request, User semossUser, AuthProvider ap) { String ip = WebUtility.inputSanitizer(ResourceUtility.getClientIp(request)); @@ -740,12 +786,6 @@ public Response userinfoGeneric(@PathParam("provider") String provider, @Context @Path("/login/salesforce") public Response loginSalesforce(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { - if (socialData.getLoginsAllowed().get("salesforce") == null - || !socialData.getLoginsAllowed().get("salesforce")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Salesforce login is not allowed"); - return WebUtility.getResponse(ret, 400); - } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -755,6 +795,22 @@ public Response loginSalesforce(@Context HttpServletRequest request, @Context Ht if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get("salesforce") == null + || !socialData.getConnectionsAllowed().get("salesforce")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Salesforce resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get("salesforce") == null || !socialData.getLoginsAllowed().get("salesforce")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Salesforce login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -764,7 +820,7 @@ public Response loginSalesforce(@Context HttpServletRequest request, @Context Ht } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.SALESFORCE) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.SALESFORCE) == null && userObj.getResourceAccessToken(AuthProvider.SALESFORCE) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -798,8 +854,12 @@ public Response loginSalesforce(@Context HttpServletRequest request, @Context Ht return null; } accessToken.setProvider(AuthProvider.SALESFORCE); - addAccessToken(accessToken, request, autoAdd); - + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); } @@ -811,14 +871,15 @@ public Response loginSalesforce(@Context HttpServletRequest request, @Context Ht if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.SALESFORCE) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.SALESFORCE) == null && userObj.getResourceAccessToken(AuthProvider.SALESFORCE) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getSalesforceRedirect(request)); return null; } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -844,12 +905,6 @@ private String getSalesforceRedirect(HttpServletRequest request) throws Unsuppor @Path("/login/surveymonkey") public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { - if (socialData.getLoginsAllowed().get("surveymonkey") == null - || !socialData.getLoginsAllowed().get("surveymonkey")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Surveymonkey login is not allowed"); - return WebUtility.getResponse(ret, 400); - } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -859,6 +914,23 @@ public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get("surveymonkey") == null + || !socialData.getConnectionsAllowed().get("surveymonkey")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "surveymonkey resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get("surveymonkey") == null + || !socialData.getLoginsAllowed().get("surveymonkey")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "surveymonkey login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -868,7 +940,7 @@ public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null && userObj.getResourceAccessToken(AuthProvider.SURVEYMONKEY) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -903,7 +975,12 @@ public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context } accessToken.setProvider(AuthProvider.SURVEYMONKEY); MonkeyProfile.fillAccessToken(accessToken, null); - addAccessToken(accessToken, request, autoAdd); + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -916,14 +993,15 @@ public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null && userObj.getResourceAccessToken(AuthProvider.SURVEYMONKEY) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getSurveyMonkeyRedirect(request)); return null; } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -950,11 +1028,6 @@ private String getSurveyMonkeyRedirect(HttpServletRequest request) throws Unsupp @Path("/login/github") public Response loginGithub(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { - if (socialData.getLoginsAllowed().get("github") == null || !socialData.getLoginsAllowed().get("github")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "GitHub login is not allowed"); - return WebUtility.getResponse(ret, 400); - } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -964,6 +1037,22 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get("github") == null + || !socialData.getConnectionsAllowed().get("github")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Github resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get("github") == null || !socialData.getLoginsAllowed().get("github")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Github login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -974,7 +1063,7 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.GITHUB) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.GITHUB) == null && userObj.getResourceAccessToken(AuthProvider.GITHUB) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code and state should match [ -~]+ (1 or more ascii) @@ -1010,7 +1099,6 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe return null; } accessToken.setProvider(AuthProvider.GITHUB); - try { GitRepoUtils.addCertForDomain(url); } catch (Exception e) { @@ -1019,9 +1107,12 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe // add specific Git values GithubTokenFiller profiler = new GithubTokenFiller(); profiler.fillAccessToken(accessToken, null, null, null, null); - - addAccessToken(accessToken, request, autoAdd); - + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); } @@ -1033,7 +1124,7 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.GITHUB) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.GITHUB) == null && userObj.getResourceAccessToken(AuthProvider.GITHUB) == null)) { // not authenticated try { GitRepoUtils.addCertForDomain("https://github.com"); @@ -1044,8 +1135,9 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe response.sendRedirect(getGithubRedirect(request)); return null; } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -1075,11 +1167,6 @@ private String getGithubRedirect(HttpServletRequest request) throws UnsupportedE @Path("/login/gitlab") public Response loginGitlab(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { - if (socialData.getLoginsAllowed().get("gitlab") == null || !socialData.getLoginsAllowed().get("gitlab")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "GitLab login is not allowed"); - return WebUtility.getResponse(ret, 400); - } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -1089,6 +1176,22 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get("gitlab") == null + || !socialData.getConnectionsAllowed().get("gitlab")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Gitlab resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get("gitlab") == null || !socialData.getLoginsAllowed().get("gitlab")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Gitlab login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1101,7 +1204,7 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe String prefix = "gitlab_"; if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.GITLAB) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.GITLAB) == null && userObj.getResourceAccessToken(AuthProvider.GITLAB) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code and state should match [ -~]+ (1 or more ascii) @@ -1146,7 +1249,12 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe true); accessToken = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanPropsArr, accessToken); - addAccessToken(accessToken, request, autoAdd); + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -1159,7 +1267,7 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.GITLAB) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.GITLAB) == null && userObj.getResourceAccessToken(AuthProvider.GITLAB) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getGitlabRedirect(request)); @@ -1186,11 +1294,12 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe userGroups.add(thisInput); } - userObj.getAccessToken(AuthProvider.GITLAB).setUserGroups(userGroups); + userObj.getAvailableAccessToken(AuthProvider.GITLAB).setUserGroups(userGroups); userObj.getAccessToken(AuthProvider.GITLAB).setUserGroupType(AuthProvider.GITLAB.toString()); } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -1232,11 +1341,6 @@ public Response loginMS(@Context HttpServletRequest request, @Context HttpServle @Path("/login/microsoft") public Response loginMicrosoft(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { - if (socialData.getLoginsAllowed().get("ms") == null || !socialData.getLoginsAllowed().get("ms")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Microsoft login is not allowed"); - return WebUtility.getResponse(ret, 400); - } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -1246,6 +1350,21 @@ public Response loginMicrosoft(@Context HttpServletRequest request, @Context Htt if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get("ms") == null || !socialData.getConnectionsAllowed().get("ms")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Microsoft resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get("ms") == null || !socialData.getLoginsAllowed().get("ms")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Microsoft login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1255,7 +1374,7 @@ public Response loginMicrosoft(@Context HttpServletRequest request, @Context Htt } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.MICROSOFT) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.MICROSOFT) == null && userObj.getResourceAccessToken(AuthProvider.MICROSOFT) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1306,7 +1425,12 @@ public Response loginMicrosoft(@Context HttpServletRequest request, @Context Htt throw new IllegalArgumentException("External users are not allowed"); } } - addAccessToken(accessToken, request, autoAdd); + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -1319,14 +1443,15 @@ public Response loginMicrosoft(@Context HttpServletRequest request, @Context Htt if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.MICROSOFT) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.MICROSOFT) == null && userObj.getResourceAccessToken(AuthProvider.MICROSOFT) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getMicrosoftRedirect(request)); return null; } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -1362,11 +1487,6 @@ private String getMicrosoftRedirect(HttpServletRequest request) throws Unsupport @Path("/login/adfs") public Response loginADFS(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { - if (socialData.getLoginsAllowed().get("adfs") == null || !socialData.getLoginsAllowed().get("adfs")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "ADFS login is not allowed"); - return WebUtility.getResponse(ret, 400); - } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -1376,6 +1496,22 @@ public Response loginADFS(@Context HttpServletRequest request, @Context HttpServ if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get("adfs") == null + || !socialData.getConnectionsAllowed().get("adfs")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "adfs resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get("adfs") == null || !socialData.getLoginsAllowed().get("adfs")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "adfs login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1386,7 +1522,7 @@ public Response loginADFS(@Context HttpServletRequest request, @Context HttpServ String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.ADFS) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.ADFS) == null && userObj.getResourceAccessToken(AuthProvider.ADFS) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1432,7 +1568,12 @@ public Response loginADFS(@Context HttpServletRequest request, @Context HttpServ String[] beanPropsArr = beanProps.split(",", -1); accessToken = (AccessToken) BeanFiller.fillFromJson(json, jsonPattern, beanPropsArr, accessToken); - addAccessToken(accessToken, request, autoAdd); + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -1445,14 +1586,15 @@ public Response loginADFS(@Context HttpServletRequest request, @Context HttpServ if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.ADFS) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.ADFS) == null && userObj.getResourceAccessToken(AuthProvider.ADFS) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getADFSRedirect(request)); return null; } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -1503,11 +1645,6 @@ private String getADFSRedirect(HttpServletRequest request) throws UnsupportedEnc @Path("/login/okta") public Response loginOkta(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { - if (socialData.getLoginsAllowed().get("okta") == null || !socialData.getLoginsAllowed().get("okta")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Okta login is not allowed"); - return WebUtility.getResponse(ret, 400); - } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -1517,6 +1654,22 @@ public Response loginOkta(@Context HttpServletRequest request, @Context HttpServ if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get("okta") == null + || !socialData.getConnectionsAllowed().get("okta")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "okta resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get("okta") == null || !socialData.getLoginsAllowed().get("okta")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "okta login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1526,7 +1679,7 @@ public Response loginOkta(@Context HttpServletRequest request, @Context HttpServ } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.MICROSOFT) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.OKTA) == null && userObj.getResourceAccessToken(AuthProvider.OKTA) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1571,7 +1724,12 @@ public Response loginOkta(@Context HttpServletRequest request, @Context HttpServ OktaTokenFiller profiler = new OktaTokenFiller(); profiler.fillAccessToken(accessToken, userinfo_url, jsonPattern, beanPropsArr, null); - addAccessToken(accessToken, request, autoAdd); + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); } @@ -1583,14 +1741,15 @@ public Response loginOkta(@Context HttpServletRequest request, @Context HttpServ if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.OKTA) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.OKTA) == null && userObj.getResourceAccessToken(AuthProvider.OKTA) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getOktaRedirect(request)); return null; } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -1621,12 +1780,6 @@ private String getOktaRedirect(HttpServletRequest request) throws UnsupportedEnc @Path("/login/siteminder") public Response loginSiteminder(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { - if (socialData.getLoginsAllowed().get("siteminder") == null - || !socialData.getLoginsAllowed().get("siteminder")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Siteminder login is not allowed"); - return WebUtility.getResponse(ret, 400); - } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -1636,6 +1789,23 @@ public Response loginSiteminder(@Context HttpServletRequest request, @Context Ht if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get("siteminder") == null + || !socialData.getConnectionsAllowed().get("siteminder")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "siteminder resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get("siteminder") == null + || !socialData.getLoginsAllowed().get("siteminder")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "siteminder login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1646,7 +1816,7 @@ public Response loginSiteminder(@Context HttpServletRequest request, @Context Ht String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.SITEMINDER) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.SITEMINDER) == null && userObj.getResourceAccessToken(AuthProvider.SITEMINDER) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1686,7 +1856,12 @@ public Response loginSiteminder(@Context HttpServletRequest request, @Context Ht } accessToken.setProvider(AuthProvider.SITEMINDER); - addAccessToken(accessToken, request, autoAdd); + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); } @@ -1698,14 +1873,15 @@ public Response loginSiteminder(@Context HttpServletRequest request, @Context Ht if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.SITEMINDER) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.SITEMINDER) == null && userObj.getResourceAccessToken(AuthProvider.SITEMINDER) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getSiteminderRedirect(request)); return null; } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -1741,11 +1917,6 @@ private String getSiteminderRedirect(HttpServletRequest request) throws Unsuppor @Path("/login/dropbox") public Response loginDropBox(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { - if (socialData.getLoginsAllowed().get("dropbox") == null || !socialData.getLoginsAllowed().get("dropbox")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Dropbox login is not allowed"); - return WebUtility.getResponse(ret, 400); - } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -1755,6 +1926,22 @@ public Response loginDropBox(@Context HttpServletRequest request, @Context HttpS if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get("dropbox") == null + || !socialData.getConnectionsAllowed().get("dropbox")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "dropbox resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get("dropbox") == null || !socialData.getLoginsAllowed().get("dropbox")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "dropbox login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1765,7 +1952,7 @@ public Response loginDropBox(@Context HttpServletRequest request, @Context HttpS String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.DROPBOX) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.DROPBOX) == null && userObj.getResourceAccessToken(AuthProvider.DROPBOX) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1799,7 +1986,12 @@ public Response loginDropBox(@Context HttpServletRequest request, @Context HttpS return null; } accessToken.setProvider(AuthProvider.DROPBOX); - addAccessToken(accessToken, request, autoAdd); + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -1812,14 +2004,15 @@ public Response loginDropBox(@Context HttpServletRequest request, @Context HttpS if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.DROPBOX) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.DROPBOX) == null && userObj.getResourceAccessToken(AuthProvider.DROPBOX) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getDBRedirect(request)); return null; } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -1849,20 +2042,31 @@ private String getDBRedirect(HttpServletRequest request) throws UnsupportedEncod @Path("/login/google") public Response loginGoogle(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { - if (socialData.getLoginsAllowed().get("google") == null || !socialData.getLoginsAllowed().get("google")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Google login is not allowed"); - return WebUtility.getResponse(ret, 400); - } /* * Try to log in the user If they are not logged in Redirect the FE */ - + HttpSession session = request.getSession(false); User userObj = null; if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get("google") == null || !socialData.getConnectionsAllowed().get("google")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Google resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get("google") == null || !socialData.getLoginsAllowed().get("google")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Google login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } + String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1873,7 +2077,7 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.GOOGLE) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.GOOGLE) == null && userObj.getResourceAccessToken(AuthProvider.GOOGLE) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1915,8 +2119,12 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe // user GoogleTokenFiller profiler = new GoogleTokenFiller(); profiler.fillAccessToken(accessToken, null, null, null, null); - addAccessToken(accessToken, request, autoAdd); - + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } // Shows how to make a google credential from an access token if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -1929,14 +2137,15 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.GOOGLE) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.GOOGLE) == null && userObj.getResourceAccessToken(AuthProvider.GOOGLE) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getGoogleRedirect(request)); return null; } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -2021,12 +2230,6 @@ private String getGoogleRedirect(HttpServletRequest request) throws UnsupportedE @Path("/login/producthunt") public Response loginProducthunt(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { - if (socialData.getLoginsAllowed().get("producthunt") == null - || !socialData.getLoginsAllowed().get("producthunt")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Producthunt login is not allowed"); - return WebUtility.getResponse(ret, 400); - } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -2036,6 +2239,23 @@ public Response loginProducthunt(@Context HttpServletRequest request, @Context H if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get("producthunt") == null + || !socialData.getConnectionsAllowed().get("producthunt")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "producthunt resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get("producthunt") == null + || !socialData.getLoginsAllowed().get("producthunt")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "producthunt login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -2046,7 +2266,7 @@ public Response loginProducthunt(@Context HttpServletRequest request, @Context H String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null && userObj.getResourceAccessToken(AuthProvider.PRODUCT_HUNT) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2080,7 +2300,12 @@ public Response loginProducthunt(@Context HttpServletRequest request, @Context H return null; } accessToken.setProvider(AuthProvider.PRODUCT_HUNT); - addAccessToken(accessToken, request, autoAdd); + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -2093,13 +2318,14 @@ public Response loginProducthunt(@Context HttpServletRequest request, @Context H if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null && userObj.getResourceAccessToken(AuthProvider.PRODUCT_HUNT) == null)) { response.setStatus(302); response.sendRedirect(getProducthuntRedirect(request)); return null; } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -2129,11 +2355,6 @@ private String getProducthuntRedirect(HttpServletRequest request) throws Unsuppo @Path("/login/linkedin") public Response loginLinkedin(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { - if (socialData.getLoginsAllowed().get("linkedin") == null || !socialData.getLoginsAllowed().get("linkedin")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "LinkedIn login is not allowed"); - return WebUtility.getResponse(ret, 400); - } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -2143,6 +2364,23 @@ public Response loginLinkedin(@Context HttpServletRequest request, @Context Http if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get("linkedin") == null + || !socialData.getConnectionsAllowed().get("linkedin")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "linkedin resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get("linkedin") == null + || !socialData.getLoginsAllowed().get("linkedin")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "linkedin login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -2153,7 +2391,7 @@ public Response loginLinkedin(@Context HttpServletRequest request, @Context Http String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.LINKEDIN) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.LINKEDIN) == null && userObj.getResourceAccessToken(AuthProvider.LINKEDIN) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2187,7 +2425,12 @@ public Response loginLinkedin(@Context HttpServletRequest request, @Context Http return null; } accessToken.setProvider(AuthProvider.LINKEDIN); - addAccessToken(accessToken, request, autoAdd); + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -2200,13 +2443,14 @@ public Response loginLinkedin(@Context HttpServletRequest request, @Context Http if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.LINKEDIN) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.LINKEDIN) == null && userObj.getResourceAccessToken(AuthProvider.LINKEDIN) == null)) { response.setStatus(302); response.sendRedirect(getLinkedinRedirect(request)); return null; } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -2240,11 +2484,6 @@ private String getLinkedinRedirect(HttpServletRequest request) throws Unsupporte @Path("/login/twitter") public Response loginTwitter(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { - if (socialData.getLoginsAllowed().get("twitter") == null || !socialData.getLoginsAllowed().get("twitter")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Twitter login is not allowed"); - return WebUtility.getResponse(ret, 400); - } // getting the bearer token on twitter for app authentication is a lot simpler // need to just combine the id and secret // base 64 and send as authorization @@ -2256,6 +2495,23 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get("twitter") == null + || !socialData.getConnectionsAllowed().get("twitter")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "twitter resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get("twitter") == null + || !socialData.getLoginsAllowed().get("twitter")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "twitter login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -2266,7 +2522,7 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.GITHUB) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.TWITTER) == null && userObj.getResourceAccessToken(AuthProvider.TWITTER) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code and state should match [ -~]+ (1 or more ascii) @@ -2303,7 +2559,12 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS } accessToken.setProvider(AuthProvider.TWITTER); - addAccessToken(accessToken, request, autoAdd); + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -2316,14 +2577,15 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.TWITTER) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.TWITTER) == null && userObj.getResourceAccessToken(AuthProvider.TWITTER) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getTwitterRedirect(request)); return null; } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -2374,11 +2636,6 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht */ provider = WebUtility.inputSanitizer(provider); - if (socialData.getLoginsAllowed().get(provider) == null || !socialData.getLoginsAllowed().get(provider)) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, provider + " login is not allowed"); - return WebUtility.getResponse(ret, 400); - } AuthProvider providerEnum = AuthProvider.getProviderFromString(provider.toUpperCase()); @@ -2387,6 +2644,23 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } + boolean isResourceConnection = (userObj != null); + + if (isResourceConnection) { + if (socialData.getConnectionsAllowed().get(provider) == null + || !socialData.getConnectionsAllowed().get(provider)) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "twitter resource connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } else { + if (socialData.getLoginsAllowed().get(provider) == null + || !socialData.getLoginsAllowed().get(provider)) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "twitter login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -2397,7 +2671,7 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(providerEnum) == null) { + if (userObj == null || (userObj.getAccessToken(providerEnum) == null && userObj.getResourceAccessToken(providerEnum) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2524,7 +2798,12 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht accessToken.setUserGroupType(providerEnum.toString()); } - addAccessToken(accessToken, request, autoAdd); + // add to specific access token based on the isResourceConnection value + if (isResourceConnection) { + addResourceAccessToken(accessToken, request, autoAdd); + } else { + addAccessToken(accessToken, request, autoAdd); + } if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -2537,14 +2816,15 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(providerEnum) == null) { + if (userObj == null || (userObj.getAccessToken(providerEnum) == null && userObj.getResourceAccessToken(providerEnum) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getGenericRedirect(provider, request)); return null; } - - setMainPageRedirect(request, response); + if (!isResourceConnection) { + setMainPageRedirect(request, response); + } return null; } @@ -3062,6 +3342,13 @@ public Response createAPIUser(@Context HttpServletRequest request) { public Response loginsAllowed(@Context HttpServletRequest request) { return WebUtility.getResponse(socialData.getLoginsAllowed(), 200); } + + @GET + @Produces("application/json") + @Path("/connectionsAllowed/") + public Response connectionsAllowed(@Context HttpServletRequest request) { + return WebUtility.getResponse(socialData.getConnectionsAllowed(), 200); + } @GET @Produces("application/json") From 487485f3d1bc434a43f9e10b305766a81884ee0c Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 Date: Wed, 12 Nov 2025 14:50:25 +0530 Subject: [PATCH 02/20] fix: updated logout logic to handle resource and login providers logout --- .../web/services/local/UserResource.java | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index e39515d8d..42bf579a2 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -205,27 +205,35 @@ public Response logout(@PathParam("provider") String provider, thisUser.getAssetProjectId(token); thisUser.getWorkspaceProjectId(token); } - removed = thisUser.dropAccessToken(token); - if (thisUser.getLogins().isEmpty()) { - noUser = true; + boolean isLoginProvider = socialData.getLoginsAllowed().getOrDefault(provider.toLowerCase(), false); + boolean isConnectionProvider = socialData.getConnectionsAllowed().getOrDefault(provider.toLowerCase(), false); + + if (!isLoginProvider && isConnectionProvider) { + removed = thisUser.dropResourceAccessToken(token); + classLogger.info("Disconnected resource provider: " + provider); } else { - request.getSession().setAttribute(Constants.SESSION_USER, thisUser); + removed = thisUser.dropAccessToken(token); + if (thisUser.getLogins().isEmpty()) { + noUser = true; + } else { + request.getSession().setAttribute(Constants.SESSION_USER, thisUser); - SyncUserAppsThread sync = new SyncUserAppsThread(workspaceEngineId, assetEngineId); - Thread t = new Thread(sync); - t.start(); + SyncUserAppsThread sync = new SyncUserAppsThread(workspaceEngineId, assetEngineId); + Thread t = new Thread(sync); + t.start(); - // put the new map for the user space - session.setAttribute(Constants.USER_WORKSPACE_IDS, thisUser.getWorkspaceEngineMap()); - session.setAttribute(Constants.USER_ASSET_IDS, thisUser.getAssetEngineMap()); + // put the new map for the user space + session.setAttribute(Constants.USER_WORKSPACE_IDS, thisUser.getWorkspaceEngineMap()); + session.setAttribute(Constants.USER_ASSET_IDS, thisUser.getAssetEngineMap()); + } } } - - // drop all the resource token for the user - thisUser.dropAllResourceAccessToken(); List nullCookies = null; if (noUser) { + // drop all the resource token if no user + thisUser.dropAllResourceAccessToken(); + // when we call session.invalidate() the UserSessionLoader will properly log is // user logout or tomcat ending session.setAttribute(UserSessionLoader.IS_USER_LOGOUT, true); From 07af2bd9ea61614459d2a5e17df86de8c9a09866 Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 Date: Wed, 12 Nov 2025 20:41:12 +0530 Subject: [PATCH 03/20] fix: updated checks for logout --- src/prerna/semoss/web/services/local/UserResource.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index 42bf579a2..8880b160d 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -205,10 +205,8 @@ public Response logout(@PathParam("provider") String provider, thisUser.getAssetProjectId(token); thisUser.getWorkspaceProjectId(token); } - boolean isLoginProvider = socialData.getLoginsAllowed().getOrDefault(provider.toLowerCase(), false); - boolean isConnectionProvider = socialData.getConnectionsAllowed().getOrDefault(provider.toLowerCase(), false); - if (!isLoginProvider && isConnectionProvider) { + if (thisUser.getResourceAccessToken(token) != null) { removed = thisUser.dropResourceAccessToken(token); classLogger.info("Disconnected resource provider: " + provider); } else { From 30ae2c509e2228e42cc40afea79195c709ba09bf Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 Date: Thu, 13 Nov 2025 19:45:51 +0530 Subject: [PATCH 04/20] fix: added logic for token removal on logout --- .../web/services/local/UserResource.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index 8880b160d..cdef72c4c 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -192,7 +192,25 @@ public Response logout(@PathParam("provider") String provider, classLogger.info("User is logging out of provider " + provider); provider = WebUtility.inputSanitizer(provider); if (provider.equalsIgnoreCase("ALL")) { - removed = true; + boolean clearedLogins = false; + boolean clearedResources = false; + + try { + thisUser.dropAllAccessToken(); + clearedLogins = true; + classLogger.info("Successfully dropped all access tokens for user"); + } catch (Exception e) { + classLogger.error("Failed to drop login tokens for user", e); + } + + try { + thisUser.dropAllResourceAccessToken(); + clearedResources = true; + classLogger.info("Successfully dropped all resource tokens for user"); + } catch (Exception e) { + classLogger.error("Failed to drop resource tokens for user", e); + } + removed = clearedLogins && clearedResources; noUser = true; } else { AuthProvider token = AuthProvider.valueOf(provider.toUpperCase()); @@ -229,9 +247,6 @@ public Response logout(@PathParam("provider") String provider, List nullCookies = null; if (noUser) { - // drop all the resource token if no user - thisUser.dropAllResourceAccessToken(); - // when we call session.invalidate() the UserSessionLoader will properly log is // user logout or tomcat ending session.setAttribute(UserSessionLoader.IS_USER_LOGOUT, true); From cedceed624a698daf7f280f32ee84ec88c6ff28a Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 Date: Fri, 14 Nov 2025 19:12:43 +0530 Subject: [PATCH 05/20] fix: Added resource connections and details --- .../web/services/config/ServerConfigurationResource.java | 3 +++ src/prerna/semoss/web/services/local/ResourceUtility.java | 1 + 2 files changed, 4 insertions(+) diff --git a/src/prerna/semoss/web/services/config/ServerConfigurationResource.java b/src/prerna/semoss/web/services/config/ServerConfigurationResource.java index 4d950392c..34deee093 100644 --- a/src/prerna/semoss/web/services/config/ServerConfigurationResource.java +++ b/src/prerna/semoss/web/services/config/ServerConfigurationResource.java @@ -243,6 +243,9 @@ private static Map getConfiguration(@Context HttpServletRequest // TODO: but not sure where this is all happening, so sending both keys for now myConfiguration.put("logins", User.getLoginNames(user)); myConfiguration.put("loginDetails", User.getLoginDetails(user)); + // current resource connections + myConfiguration.put("connections", User.getConnectionsNames(user)); + myConfiguration.put("connectionDetails", User.getConnectionDetails(user)); // themes myConfiguration.put("theme", AdminThemeUtils.getActiveAdminTheme()); // add if we are using csrf diff --git a/src/prerna/semoss/web/services/local/ResourceUtility.java b/src/prerna/semoss/web/services/local/ResourceUtility.java index 5244d5783..ff34e64ef 100644 --- a/src/prerna/semoss/web/services/local/ResourceUtility.java +++ b/src/prerna/semoss/web/services/local/ResourceUtility.java @@ -36,6 +36,7 @@ public class ResourceUtility { allowAccessWithoutLogin.add("config/fetchCsrf"); allowAccessWithoutLogin.add("auth/logins"); allowAccessWithoutLogin.add("auth/loginsAllowed"); + allowAccessWithoutLogin.add("auth/connections"); allowAccessWithoutLogin.add("auth/connectionsAllowed"); allowAccessWithoutLogin.add("auth/login"); allowAccessWithoutLogin.add("auth/loginLDAP"); From 3562472e51d1471bffd35fe9dacaa634d9529efb Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 Date: Sun, 16 Nov 2025 16:39:19 +0530 Subject: [PATCH 06/20] fix: used setMainPageRedirect for all logins types and update use of availableAccessToken for userinfo --- .../web/services/local/UserResource.java | 84 ++++++++----------- 1 file changed, 35 insertions(+), 49 deletions(-) diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index cdef72c4c..5f059e598 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -427,7 +427,7 @@ public Response userinfoGoogle(@Context HttpServletRequest request) { String jsonPattern = "[name, picture]"; String accessString = null; try { - AccessToken googleToken = semossUser.getAccessToken(AuthProvider.GOOGLE); + AccessToken googleToken = semossUser.getAvailableAccessToken(AuthProvider.GOOGLE); accessString = googleToken.getAccess_token(); } catch (Exception e) { ret.put(Constants.ERROR_MESSAGE, "Log into your Google account"); @@ -495,7 +495,7 @@ public Response userinfoMicrosoft(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken msToken = semossUser.getAccessToken(AuthProvider.MICROSOFT); + AccessToken msToken = semossUser.getAvailableAccessToken(AuthProvider.MICROSOFT); accessString = msToken.getAccess_token(); String url = "https://graph.microsoft.com/v1.0/me/"; String output = HttpHelperUtility.makeGetCall(url, accessString, null, true); @@ -547,7 +547,7 @@ public Response userinfoADFS(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken adfsToken = semossUser.getAccessToken(AuthProvider.ADFS); + AccessToken adfsToken = semossUser.getAvailableAccessToken(AuthProvider.ADFS); accessString = adfsToken.getAccess_token(); String json = decodeTokenPayload(adfsToken.getAccess_token()); adfsToken = (AccessToken) BeanFiller.fillFromJson(json, jsonPattern, beanPropsArr, adfsToken); @@ -593,7 +593,7 @@ public Response userinfoDropbox(@Context HttpServletRequest request) { String jsonPattern = "[name.display_name, profile_photo_url]"; String accessString = null; try { - AccessToken dropToken = semossUser.getAccessToken(AuthProvider.DROPBOX); + AccessToken dropToken = semossUser.getAvailableAccessToken(AuthProvider.DROPBOX); accessString = dropToken.getAccess_token(); } catch (Exception e) { ret.put(Constants.ERROR_MESSAGE, "Log into your DropBox account"); @@ -651,7 +651,7 @@ public Response userinfoGithub(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken gitToken = semossUser.getAccessToken(AuthProvider.GITHUB); + AccessToken gitToken = semossUser.getAvailableAccessToken(AuthProvider.GITHUB); accessString = gitToken.getAccess_token(); } catch (Exception e) { ret.put(Constants.ERROR_MESSAGE, "Log into your Github account"); @@ -703,7 +703,7 @@ public Response userinfoOkta(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken accessToken = semossUser.getAccessToken(AuthProvider.OKTA); + AccessToken accessToken = semossUser.getAvailableAccessToken(AuthProvider.OKTA); accessString = accessToken.getAccess_token(); String userInfoURL = socialData.getProperty(prefix + "userinfo_url"); String socialBeanProps = socialData.getProperty(prefix + "beanProps"); @@ -772,7 +772,7 @@ public Response userinfoGeneric(@PathParam("provider") String provider, @Context String accessString = null; try { - AccessToken genericToken = semossUser.getAccessToken(providerEnum); + AccessToken genericToken = semossUser.getAvailableAccessToken(providerEnum); accessString = genericToken.getAccess_token(); // String url = "https://graph.microsoft.com/v1.0/me/"; String output = HttpHelperUtility.makeGetCall(userInfoURL, accessString, null, true); @@ -898,9 +898,8 @@ public Response loginSalesforce(@Context HttpServletRequest request, @Context Ht response.sendRedirect(getSalesforceRedirect(request)); return null; } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } @@ -1020,9 +1019,8 @@ public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context response.sendRedirect(getSurveyMonkeyRedirect(request)); return null; } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } @@ -1156,9 +1154,8 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe response.sendRedirect(getGithubRedirect(request)); return null; } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } @@ -1318,9 +1315,8 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe userObj.getAvailableAccessToken(AuthProvider.GITLAB).setUserGroups(userGroups); userObj.getAccessToken(AuthProvider.GITLAB).setUserGroupType(AuthProvider.GITLAB.toString()); } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } @@ -1470,9 +1466,8 @@ public Response loginMicrosoft(@Context HttpServletRequest request, @Context Htt response.sendRedirect(getMicrosoftRedirect(request)); return null; } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } @@ -1613,9 +1608,8 @@ public Response loginADFS(@Context HttpServletRequest request, @Context HttpServ response.sendRedirect(getADFSRedirect(request)); return null; } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } @@ -1768,9 +1762,8 @@ public Response loginOkta(@Context HttpServletRequest request, @Context HttpServ response.sendRedirect(getOktaRedirect(request)); return null; } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } @@ -1900,9 +1893,8 @@ public Response loginSiteminder(@Context HttpServletRequest request, @Context Ht response.sendRedirect(getSiteminderRedirect(request)); return null; } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } @@ -2031,9 +2023,8 @@ public Response loginDropBox(@Context HttpServletRequest request, @Context HttpS response.sendRedirect(getDBRedirect(request)); return null; } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } @@ -2164,9 +2155,8 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe response.sendRedirect(getGoogleRedirect(request)); return null; } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } @@ -2344,9 +2334,8 @@ public Response loginProducthunt(@Context HttpServletRequest request, @Context H response.sendRedirect(getProducthuntRedirect(request)); return null; } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } @@ -2469,9 +2458,8 @@ public Response loginLinkedin(@Context HttpServletRequest request, @Context Http response.sendRedirect(getLinkedinRedirect(request)); return null; } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } @@ -2604,9 +2592,8 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS response.sendRedirect(getTwitterRedirect(request)); return null; } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } @@ -2843,9 +2830,8 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht response.sendRedirect(getGenericRedirect(provider, request)); return null; } - if (!isResourceConnection) { - setMainPageRedirect(request, response); - } + + setMainPageRedirect(request, response); return null; } From 11d3ea4d1e40888a3e81ccc78c4813bfa8f9e46c Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 Date: Mon, 17 Nov 2025 20:24:26 +0530 Subject: [PATCH 07/20] fix: Updated checks and use getAccessToken to fetch tokens --- .../web/services/local/UserResource.java | 75 ++++++++++--------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index 5f059e598..191a7693f 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -427,7 +427,7 @@ public Response userinfoGoogle(@Context HttpServletRequest request) { String jsonPattern = "[name, picture]"; String accessString = null; try { - AccessToken googleToken = semossUser.getAvailableAccessToken(AuthProvider.GOOGLE); + AccessToken googleToken = semossUser.getAccessToken(AuthProvider.GOOGLE); accessString = googleToken.getAccess_token(); } catch (Exception e) { ret.put(Constants.ERROR_MESSAGE, "Log into your Google account"); @@ -495,7 +495,7 @@ public Response userinfoMicrosoft(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken msToken = semossUser.getAvailableAccessToken(AuthProvider.MICROSOFT); + AccessToken msToken = semossUser.getAccessToken(AuthProvider.MICROSOFT); accessString = msToken.getAccess_token(); String url = "https://graph.microsoft.com/v1.0/me/"; String output = HttpHelperUtility.makeGetCall(url, accessString, null, true); @@ -547,7 +547,7 @@ public Response userinfoADFS(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken adfsToken = semossUser.getAvailableAccessToken(AuthProvider.ADFS); + AccessToken adfsToken = semossUser.getAccessToken(AuthProvider.ADFS); accessString = adfsToken.getAccess_token(); String json = decodeTokenPayload(adfsToken.getAccess_token()); adfsToken = (AccessToken) BeanFiller.fillFromJson(json, jsonPattern, beanPropsArr, adfsToken); @@ -593,7 +593,7 @@ public Response userinfoDropbox(@Context HttpServletRequest request) { String jsonPattern = "[name.display_name, profile_photo_url]"; String accessString = null; try { - AccessToken dropToken = semossUser.getAvailableAccessToken(AuthProvider.DROPBOX); + AccessToken dropToken = semossUser.getAccessToken(AuthProvider.DROPBOX); accessString = dropToken.getAccess_token(); } catch (Exception e) { ret.put(Constants.ERROR_MESSAGE, "Log into your DropBox account"); @@ -651,7 +651,7 @@ public Response userinfoGithub(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken gitToken = semossUser.getAvailableAccessToken(AuthProvider.GITHUB); + AccessToken gitToken = semossUser.getAccessToken(AuthProvider.GITHUB); accessString = gitToken.getAccess_token(); } catch (Exception e) { ret.put(Constants.ERROR_MESSAGE, "Log into your Github account"); @@ -703,7 +703,7 @@ public Response userinfoOkta(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken accessToken = semossUser.getAvailableAccessToken(AuthProvider.OKTA); + AccessToken accessToken = semossUser.getAccessToken(AuthProvider.OKTA); accessString = accessToken.getAccess_token(); String userInfoURL = socialData.getProperty(prefix + "userinfo_url"); String socialBeanProps = socialData.getProperty(prefix + "beanProps"); @@ -772,7 +772,7 @@ public Response userinfoGeneric(@PathParam("provider") String provider, @Context String accessString = null; try { - AccessToken genericToken = semossUser.getAvailableAccessToken(providerEnum); + AccessToken genericToken = semossUser.getAccessToken(providerEnum); accessString = genericToken.getAccess_token(); // String url = "https://graph.microsoft.com/v1.0/me/"; String output = HttpHelperUtility.makeGetCall(userInfoURL, accessString, null, true); @@ -841,7 +841,7 @@ public Response loginSalesforce(@Context HttpServletRequest request, @Context Ht } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.SALESFORCE) == null && userObj.getResourceAccessToken(AuthProvider.SALESFORCE) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.SALESFORCE) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -892,7 +892,7 @@ public Response loginSalesforce(@Context HttpServletRequest request, @Context Ht if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.SALESFORCE) == null && userObj.getResourceAccessToken(AuthProvider.SALESFORCE) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.SALESFORCE) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getSalesforceRedirect(request)); @@ -916,7 +916,8 @@ private String getSalesforceRedirect(HttpServletRequest request) throws Unsuppor } return redirectUrl; } - + + /** * Logs user in through survey monkey */ @@ -960,7 +961,7 @@ public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null && userObj.getResourceAccessToken(AuthProvider.SURVEYMONKEY) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1013,7 +1014,7 @@ public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null && userObj.getResourceAccessToken(AuthProvider.SURVEYMONKEY) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getSurveyMonkeyRedirect(request)); @@ -1082,7 +1083,7 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.GITHUB) == null && userObj.getResourceAccessToken(AuthProvider.GITHUB) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.GITHUB) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code and state should match [ -~]+ (1 or more ascii) @@ -1143,7 +1144,7 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.GITHUB) == null && userObj.getResourceAccessToken(AuthProvider.GITHUB) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.GITHUB) == null) { // not authenticated try { GitRepoUtils.addCertForDomain("https://github.com"); @@ -1222,7 +1223,7 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe String prefix = "gitlab_"; if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.GITLAB) == null && userObj.getResourceAccessToken(AuthProvider.GITLAB) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.GITLAB) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code and state should match [ -~]+ (1 or more ascii) @@ -1285,7 +1286,7 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.GITLAB) == null && userObj.getResourceAccessToken(AuthProvider.GITLAB) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.GITLAB) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getGitlabRedirect(request)); @@ -1312,7 +1313,7 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe userGroups.add(thisInput); } - userObj.getAvailableAccessToken(AuthProvider.GITLAB).setUserGroups(userGroups); + userObj.getAccessToken(AuthProvider.GITLAB).setUserGroups(userGroups); userObj.getAccessToken(AuthProvider.GITLAB).setUserGroupType(AuthProvider.GITLAB.toString()); } @@ -1391,7 +1392,7 @@ public Response loginMicrosoft(@Context HttpServletRequest request, @Context Htt } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.MICROSOFT) == null && userObj.getResourceAccessToken(AuthProvider.MICROSOFT) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.MICROSOFT) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1460,7 +1461,7 @@ public Response loginMicrosoft(@Context HttpServletRequest request, @Context Htt if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.MICROSOFT) == null && userObj.getResourceAccessToken(AuthProvider.MICROSOFT) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.MICROSOFT) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getMicrosoftRedirect(request)); @@ -1538,7 +1539,7 @@ public Response loginADFS(@Context HttpServletRequest request, @Context HttpServ String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.ADFS) == null && userObj.getResourceAccessToken(AuthProvider.ADFS) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.ADFS) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1602,7 +1603,7 @@ public Response loginADFS(@Context HttpServletRequest request, @Context HttpServ if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.ADFS) == null && userObj.getResourceAccessToken(AuthProvider.ADFS) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.ADFS) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getADFSRedirect(request)); @@ -1694,7 +1695,7 @@ public Response loginOkta(@Context HttpServletRequest request, @Context HttpServ } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.OKTA) == null && userObj.getResourceAccessToken(AuthProvider.OKTA) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.OKTA) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1756,7 +1757,7 @@ public Response loginOkta(@Context HttpServletRequest request, @Context HttpServ if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.OKTA) == null && userObj.getResourceAccessToken(AuthProvider.OKTA) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.OKTA) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getOktaRedirect(request)); @@ -1830,7 +1831,7 @@ public Response loginSiteminder(@Context HttpServletRequest request, @Context Ht String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.SITEMINDER) == null && userObj.getResourceAccessToken(AuthProvider.SITEMINDER) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.SITEMINDER) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1887,7 +1888,7 @@ public Response loginSiteminder(@Context HttpServletRequest request, @Context Ht if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.SITEMINDER) == null && userObj.getResourceAccessToken(AuthProvider.SITEMINDER) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.SITEMINDER) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getSiteminderRedirect(request)); @@ -1965,7 +1966,7 @@ public Response loginDropBox(@Context HttpServletRequest request, @Context HttpS String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.DROPBOX) == null && userObj.getResourceAccessToken(AuthProvider.DROPBOX) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.DROPBOX) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2017,7 +2018,7 @@ public Response loginDropBox(@Context HttpServletRequest request, @Context HttpS if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.DROPBOX) == null && userObj.getResourceAccessToken(AuthProvider.DROPBOX) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.DROPBOX) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getDBRedirect(request)); @@ -2089,7 +2090,7 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.GOOGLE) == null && userObj.getResourceAccessToken(AuthProvider.GOOGLE) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.GOOGLE) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2149,7 +2150,7 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.GOOGLE) == null && userObj.getResourceAccessToken(AuthProvider.GOOGLE) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.GOOGLE) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getGoogleRedirect(request)); @@ -2277,7 +2278,7 @@ public Response loginProducthunt(@Context HttpServletRequest request, @Context H String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null && userObj.getResourceAccessToken(AuthProvider.PRODUCT_HUNT) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2329,7 +2330,7 @@ public Response loginProducthunt(@Context HttpServletRequest request, @Context H if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null && userObj.getResourceAccessToken(AuthProvider.PRODUCT_HUNT) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null) { response.setStatus(302); response.sendRedirect(getProducthuntRedirect(request)); return null; @@ -2401,7 +2402,7 @@ public Response loginLinkedin(@Context HttpServletRequest request, @Context Http String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.LINKEDIN) == null && userObj.getResourceAccessToken(AuthProvider.LINKEDIN) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.LINKEDIN) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2453,7 +2454,7 @@ public Response loginLinkedin(@Context HttpServletRequest request, @Context Http if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.LINKEDIN) == null && userObj.getResourceAccessToken(AuthProvider.LINKEDIN) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.LINKEDIN) == null) { response.setStatus(302); response.sendRedirect(getLinkedinRedirect(request)); return null; @@ -2531,7 +2532,7 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.TWITTER) == null && userObj.getResourceAccessToken(AuthProvider.TWITTER) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.TWITTER) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code and state should match [ -~]+ (1 or more ascii) @@ -2586,7 +2587,7 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.TWITTER) == null && userObj.getResourceAccessToken(AuthProvider.TWITTER) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.TWITTER) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getTwitterRedirect(request)); @@ -2679,7 +2680,7 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(providerEnum) == null && userObj.getResourceAccessToken(providerEnum) == null)) { + if (userObj == null || userObj.getAccessToken(providerEnum) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2824,7 +2825,7 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(providerEnum) == null && userObj.getResourceAccessToken(providerEnum) == null)) { + if (userObj == null || userObj.getAccessToken(providerEnum) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getGenericRedirect(provider, request)); From 56f75fabf5ba648020ff1caa4cbb00e4c743d4ea Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 Date: Tue, 27 Jan 2026 16:57:48 +0530 Subject: [PATCH 08/20] fix: Added getAvailableAccessToken logic --- .../web/services/local/UserResource.java | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index ccd274f9a..837de626e 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -432,7 +432,7 @@ public Response userinfoGoogle(@Context HttpServletRequest request) { String jsonPattern = "[name, picture]"; String accessString = null; try { - AccessToken googleToken = semossUser.getAccessToken(AuthProvider.GOOGLE); + AccessToken googleToken = semossUser.getAvailableAccessToken(AuthProvider.GOOGLE); accessString = googleToken.getAccess_token(); } catch (Exception e) { ret.put(Constants.ERROR_MESSAGE, "Log into your Google account"); @@ -500,7 +500,7 @@ public Response userinfoMicrosoft(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken msToken = semossUser.getAccessToken(AuthProvider.MICROSOFT); + AccessToken msToken = semossUser.getAvailableAccessToken(AuthProvider.MICROSOFT); accessString = msToken.getAccess_token(); String url = "https://graph.microsoft.com/v1.0/me/"; String output = HttpHelperUtility.makeGetCall(url, accessString, null, true); @@ -552,7 +552,7 @@ public Response userinfoADFS(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken adfsToken = semossUser.getAccessToken(AuthProvider.ADFS); + AccessToken adfsToken = semossUser.getAvailableAccessToken(AuthProvider.ADFS); accessString = adfsToken.getAccess_token(); String json = decodeTokenPayload(adfsToken.getAccess_token()); adfsToken = (AccessToken) BeanFiller.fillFromJson(json, jsonPattern, beanPropsArr, adfsToken); @@ -598,7 +598,7 @@ public Response userinfoDropbox(@Context HttpServletRequest request) { String jsonPattern = "[name.display_name, profile_photo_url]"; String accessString = null; try { - AccessToken dropToken = semossUser.getAccessToken(AuthProvider.DROPBOX); + AccessToken dropToken = semossUser.getAvailableAccessToken(AuthProvider.DROPBOX); accessString = dropToken.getAccess_token(); } catch (Exception e) { ret.put(Constants.ERROR_MESSAGE, "Log into your DropBox account"); @@ -656,7 +656,7 @@ public Response userinfoGithub(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken gitToken = semossUser.getAccessToken(AuthProvider.GITHUB); + AccessToken gitToken = semossUser.getAvailableAccessToken(AuthProvider.GITHUB); accessString = gitToken.getAccess_token(); } catch (Exception e) { ret.put(Constants.ERROR_MESSAGE, "Log into your Github account"); @@ -708,7 +708,7 @@ public Response userinfoOkta(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken accessToken = semossUser.getAccessToken(AuthProvider.OKTA); + AccessToken accessToken = semossUser.getAvailableAccessToken(AuthProvider.OKTA); accessString = accessToken.getAccess_token(); String userInfoURL = socialData.getProperty(prefix + "userinfo_url"); String socialBeanProps = socialData.getProperty(prefix + "beanProps"); @@ -777,7 +777,7 @@ public Response userinfoGeneric(@PathParam("provider") String provider, @Context String accessString = null; try { - AccessToken genericToken = semossUser.getAccessToken(providerEnum); + AccessToken genericToken = semossUser.getAvailableAccessToken(providerEnum); accessString = genericToken.getAccess_token(); // String url = "https://graph.microsoft.com/v1.0/me/"; String output = HttpHelperUtility.makeGetCall(userInfoURL, accessString, null, true); @@ -846,7 +846,7 @@ public Response loginSalesforce(@Context HttpServletRequest request, @Context Ht } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.SALESFORCE) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.SALESFORCE) == null && userObj.getResourceAccessToken(AuthProvider.SALESFORCE) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -897,7 +897,7 @@ public Response loginSalesforce(@Context HttpServletRequest request, @Context Ht if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.SALESFORCE) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.SALESFORCE) == null && userObj.getResourceAccessToken(AuthProvider.SALESFORCE) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getSalesforceRedirect(request)); @@ -966,7 +966,7 @@ public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null && userObj.getResourceAccessToken(AuthProvider.SURVEYMONKEY) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1019,7 +1019,7 @@ public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null && userObj.getResourceAccessToken(AuthProvider.SURVEYMONKEY) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getSurveyMonkeyRedirect(request)); @@ -1088,7 +1088,7 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.GITHUB) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.GITHUB) == null && userObj.getResourceAccessToken(AuthProvider.GITHUB) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code and state should match [ -~]+ (1 or more ascii) @@ -1149,7 +1149,7 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.GITHUB) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.GITHUB) == null && userObj.getResourceAccessToken(AuthProvider.GITHUB) == null)) { // not authenticated try { GitRepoUtils.addCertForDomain("https://github.com"); @@ -1228,7 +1228,7 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe String prefix = "gitlab_"; if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.GITLAB) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.GITLAB) == null && userObj.getResourceAccessToken(AuthProvider.GITLAB) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code and state should match [ -~]+ (1 or more ascii) @@ -1291,7 +1291,7 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.GITLAB) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.GITLAB) == null && userObj.getResourceAccessToken(AuthProvider.GITLAB) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getGitlabRedirect(request)); @@ -1302,7 +1302,7 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe // get groups String group_url = socialData.getProperty(prefix + "group_url"); String groupsJson = HttpHelperUtility.makeGetCall(group_url, - userObj.getAccessToken(AuthProvider.GITLAB).getAccess_token()); + userObj.getAvailableAccessToken(AuthProvider.GITLAB).getAccess_token()); System.out.println(groupsJson); String groupJsonPattern = socialData.getProperty(prefix + "groupJsonPattern"); // String beanProps = socialData.getProperty(prefix + "groupBeanProps"); @@ -1318,8 +1318,8 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe userGroups.add(thisInput); } - userObj.getAccessToken(AuthProvider.GITLAB).setUserGroups(userGroups); - userObj.getAccessToken(AuthProvider.GITLAB).setUserGroupType(AuthProvider.GITLAB.toString()); + userObj.getAvailableAccessToken(AuthProvider.GITLAB).setUserGroups(userGroups); + userObj.getAvailableAccessToken(AuthProvider.GITLAB).setUserGroupType(AuthProvider.GITLAB.toString()); } setMainPageRedirect(request, response); @@ -1397,7 +1397,7 @@ public Response loginMicrosoft(@Context HttpServletRequest request, @Context Htt } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.MICROSOFT) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.MICROSOFT) == null && userObj.getResourceAccessToken(AuthProvider.MICROSOFT) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1466,7 +1466,7 @@ public Response loginMicrosoft(@Context HttpServletRequest request, @Context Htt if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.MICROSOFT) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.MICROSOFT) == null && userObj.getResourceAccessToken(AuthProvider.MICROSOFT) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getMicrosoftRedirect(request)); @@ -1544,7 +1544,7 @@ public Response loginADFS(@Context HttpServletRequest request, @Context HttpServ String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.ADFS) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.ADFS) == null && userObj.getResourceAccessToken(AuthProvider.ADFS) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1608,7 +1608,7 @@ public Response loginADFS(@Context HttpServletRequest request, @Context HttpServ if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.ADFS) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.ADFS) == null && userObj.getResourceAccessToken(AuthProvider.ADFS) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getADFSRedirect(request)); @@ -1700,7 +1700,7 @@ public Response loginOkta(@Context HttpServletRequest request, @Context HttpServ } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.OKTA) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.OKTA) == null && userObj.getResourceAccessToken(AuthProvider.OKTA) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1762,7 +1762,7 @@ public Response loginOkta(@Context HttpServletRequest request, @Context HttpServ if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.OKTA) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.OKTA) == null && userObj.getResourceAccessToken(AuthProvider.OKTA) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getOktaRedirect(request)); @@ -1836,7 +1836,7 @@ public Response loginSiteminder(@Context HttpServletRequest request, @Context Ht String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.SITEMINDER) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.SITEMINDER) == null && userObj.getResourceAccessToken(AuthProvider.SITEMINDER) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1893,7 +1893,7 @@ public Response loginSiteminder(@Context HttpServletRequest request, @Context Ht if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.SITEMINDER) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.SITEMINDER) == null && userObj.getResourceAccessToken(AuthProvider.SITEMINDER) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getSiteminderRedirect(request)); @@ -1971,7 +1971,7 @@ public Response loginDropBox(@Context HttpServletRequest request, @Context HttpS String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.DROPBOX) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.DROPBOX) == null && userObj.getResourceAccessToken(AuthProvider.DROPBOX) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2023,7 +2023,7 @@ public Response loginDropBox(@Context HttpServletRequest request, @Context HttpS if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.DROPBOX) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.DROPBOX) == null && userObj.getResourceAccessToken(AuthProvider.DROPBOX) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getDBRedirect(request)); @@ -2095,7 +2095,7 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.GOOGLE) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.GOOGLE) == null && userObj.getResourceAccessToken(AuthProvider.GOOGLE) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2155,7 +2155,7 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.GOOGLE) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.GOOGLE) == null && userObj.getResourceAccessToken(AuthProvider.GOOGLE) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getGoogleRedirect(request)); @@ -2283,7 +2283,7 @@ public Response loginProducthunt(@Context HttpServletRequest request, @Context H String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null && userObj.getResourceAccessToken(AuthProvider.PRODUCT_HUNT) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2335,7 +2335,7 @@ public Response loginProducthunt(@Context HttpServletRequest request, @Context H if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null && userObj.getResourceAccessToken(AuthProvider.PRODUCT_HUNT) == null)) { response.setStatus(302); response.sendRedirect(getProducthuntRedirect(request)); return null; @@ -2407,7 +2407,7 @@ public Response loginLinkedin(@Context HttpServletRequest request, @Context Http String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.LINKEDIN) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.LINKEDIN) == null && userObj.getResourceAccessToken(AuthProvider.LINKEDIN) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2459,7 +2459,7 @@ public Response loginLinkedin(@Context HttpServletRequest request, @Context Http if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.LINKEDIN) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.LINKEDIN) == null && userObj.getResourceAccessToken(AuthProvider.LINKEDIN) == null)) { response.setStatus(302); response.sendRedirect(getLinkedinRedirect(request)); return null; @@ -2537,7 +2537,7 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(AuthProvider.TWITTER) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.TWITTER) == null && userObj.getResourceAccessToken(AuthProvider.TWITTER) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code and state should match [ -~]+ (1 or more ascii) @@ -2592,7 +2592,7 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(AuthProvider.TWITTER) == null) { + if (userObj == null || (userObj.getAccessToken(AuthProvider.TWITTER) == null && userObj.getResourceAccessToken(AuthProvider.TWITTER) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getTwitterRedirect(request)); @@ -2685,7 +2685,7 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || userObj.getAccessToken(providerEnum) == null) { + if (userObj == null || (userObj.getAccessToken(providerEnum) == null && userObj.getResourceAccessToken(providerEnum) == null)) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2830,7 +2830,7 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || userObj.getAccessToken(providerEnum) == null) { + if (userObj == null || (userObj.getAccessToken(providerEnum) == null && userObj.getResourceAccessToken(providerEnum) == null)) { // not authenticated response.setStatus(302); response.sendRedirect(getGenericRedirect(provider, request)); @@ -3586,7 +3586,7 @@ public Response show(@Context HttpServletRequest request, @Context HttpServletRe if (session != null) { User user = (User) session.getAttribute(Constants.SESSION_USER); if (user != null) { - AccessToken token = user.getAccessToken(user.getPrimaryLogin()); + AccessToken token = user.getResourceAccessToken(user.getPrimaryLogin()); output.put("name", token.getId()); output.put("warning", "null principal - grab from user"); } From 1aa346c48eb42bbd0e9ffec15bb38e0caec34e44 Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 Date: Thu, 5 Feb 2026 17:38:03 +0530 Subject: [PATCH 09/20] fix: update login and logout logic --- .../web/services/local/UserResource.java | 704 +++++++----------- 1 file changed, 283 insertions(+), 421 deletions(-) diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index 837de626e..571e2bd00 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -186,66 +186,86 @@ public Response logout(@PathParam("provider") String provider, Map ret = new HashMap<>(); ret.put("success", false); ret.put(Constants.ERROR_MESSAGE, "No user is currently logged in the session"); - return WebUtility.getResponse(ret, 400); + return WebUtility.getResponse(ret, 401); } // log the user logout classLogger.info("User is logging out of provider " + provider); provider = WebUtility.inputSanitizer(provider); if (provider.equalsIgnoreCase("ALL")) { - boolean clearedLogins = false; - boolean clearedResources = false; - - try { - thisUser.dropAllAccessToken(); - clearedLogins = true; - classLogger.info("Successfully dropped all access tokens for user"); - } catch (Exception e) { - classLogger.error("Failed to drop login tokens for user", e); - } - + // Drop all resource access tokens try { thisUser.dropAllResourceAccessToken(); - clearedResources = true; classLogger.info("Successfully dropped all resource tokens for user"); } catch (Exception e) { - classLogger.error("Failed to drop resource tokens for user", e); + classLogger.error("Failed to drop resource tokens for user", e); } - removed = clearedLogins && clearedResources; + removed = true; noUser = true; } else { - AuthProvider token = AuthProvider.valueOf(provider.toUpperCase()); - String assetEngineId = null; - String workspaceEngineId = null; + AuthProvider token = null; + try { + token = AuthProvider.valueOf(provider.toUpperCase()); + } catch (IllegalArgumentException e) { + classLogger.error("Invalid provider: " + provider, e); + Map ret = new HashMap<>(); + ret.put("success", false); + ret.put(Constants.ERROR_MESSAGE, "Invalid provider: " + provider); + return WebUtility.getResponse(ret, 400); + } + + // Check if this is a login token or a resource access token + boolean isLoginToken = thisUser.getAccessToken(token) != null; + boolean isResourceToken = thisUser.getResourceAccessToken(token) != null; - // TODO: what does this part do? - // TODO: feel like when logout need to adjust the asset id - if (thisUser.getLogins().size() == 1) { - thisUser.getAssetProjectId(token); - thisUser.getWorkspaceProjectId(token); + if (!isLoginToken && !isResourceToken) { + // Provider not found in either login or resource tokens + Map ret = new HashMap<>(); + ret.put("success", false); + ret.put(Constants.ERROR_MESSAGE, "Provider " + provider + " is not associated with this user"); + return WebUtility.getResponse(ret, 400); } - if (thisUser.getResourceAccessToken(token) != null) { + // Handle resource token removal (takes precedence as it's safer) + if (isResourceToken && !isLoginToken) { + // This is ONLY a resource access token (for data integrations), just remove it removed = thisUser.dropResourceAccessToken(token); - classLogger.info("Disconnected resource provider: " + provider); - } else { + classLogger.info("User disconnected from resource provider " + provider); + } else if (isLoginToken) { + // This is a login token (may also have resource token) + // Remove both login and resource tokens if both exist + String assetEngineId = null; + String workspaceEngineId = null; + + // Capture workspace/asset IDs before dropping if this is the last login + if (thisUser.getLogins().size() == 1) { + assetEngineId = thisUser.getAssetProjectId(token); + workspaceEngineId = thisUser.getWorkspaceProjectId(token); + } removed = thisUser.dropAccessToken(token); + + // Also remove resource token if it exists + if (isResourceToken) { + thisUser.dropResourceAccessToken(token); + classLogger.info("Removed both login and resource tokens for provider " + provider); + } + if (thisUser.getLogins().isEmpty()) { noUser = true; } else { - request.getSession().setAttribute(Constants.SESSION_USER, thisUser); + session.setAttribute(Constants.SESSION_USER, thisUser); SyncUserAppsThread sync = new SyncUserAppsThread(workspaceEngineId, assetEngineId); Thread t = new Thread(sync); t.start(); - // put the new map for the user space + // Update the workspace and asset maps session.setAttribute(Constants.USER_WORKSPACE_IDS, thisUser.getWorkspaceEngineMap()); session.setAttribute(Constants.USER_ASSET_IDS, thisUser.getAssetEngineMap()); } } } - + List nullCookies = null; if (noUser) { // when we call session.invalidate() the UserSessionLoader will properly log is @@ -306,7 +326,7 @@ public Response logout(@PathParam("provider") String provider, return WebUtility.getResponseNoCache(ret, 200, nullCookies.toArray(new NewCookie[] {})); } - + /** * Method to add an access token to a user * @@ -432,7 +452,7 @@ public Response userinfoGoogle(@Context HttpServletRequest request) { String jsonPattern = "[name, picture]"; String accessString = null; try { - AccessToken googleToken = semossUser.getAvailableAccessToken(AuthProvider.GOOGLE); + AccessToken googleToken = semossUser.getAccessToken(AuthProvider.GOOGLE); accessString = googleToken.getAccess_token(); } catch (Exception e) { ret.put(Constants.ERROR_MESSAGE, "Log into your Google account"); @@ -500,7 +520,7 @@ public Response userinfoMicrosoft(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken msToken = semossUser.getAvailableAccessToken(AuthProvider.MICROSOFT); + AccessToken msToken = semossUser.getAccessToken(AuthProvider.MICROSOFT); accessString = msToken.getAccess_token(); String url = "https://graph.microsoft.com/v1.0/me/"; String output = HttpHelperUtility.makeGetCall(url, accessString, null, true); @@ -552,7 +572,7 @@ public Response userinfoADFS(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken adfsToken = semossUser.getAvailableAccessToken(AuthProvider.ADFS); + AccessToken adfsToken = semossUser.getAccessToken(AuthProvider.ADFS); accessString = adfsToken.getAccess_token(); String json = decodeTokenPayload(adfsToken.getAccess_token()); adfsToken = (AccessToken) BeanFiller.fillFromJson(json, jsonPattern, beanPropsArr, adfsToken); @@ -598,7 +618,7 @@ public Response userinfoDropbox(@Context HttpServletRequest request) { String jsonPattern = "[name.display_name, profile_photo_url]"; String accessString = null; try { - AccessToken dropToken = semossUser.getAvailableAccessToken(AuthProvider.DROPBOX); + AccessToken dropToken = semossUser.getAccessToken(AuthProvider.DROPBOX); accessString = dropToken.getAccess_token(); } catch (Exception e) { ret.put(Constants.ERROR_MESSAGE, "Log into your DropBox account"); @@ -656,7 +676,7 @@ public Response userinfoGithub(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken gitToken = semossUser.getAvailableAccessToken(AuthProvider.GITHUB); + AccessToken gitToken = semossUser.getAccessToken(AuthProvider.GITHUB); accessString = gitToken.getAccess_token(); } catch (Exception e) { ret.put(Constants.ERROR_MESSAGE, "Log into your Github account"); @@ -708,7 +728,7 @@ public Response userinfoOkta(@Context HttpServletRequest request) { String accessString = null; try { - AccessToken accessToken = semossUser.getAvailableAccessToken(AuthProvider.OKTA); + AccessToken accessToken = semossUser.getAccessToken(AuthProvider.OKTA); accessString = accessToken.getAccess_token(); String userInfoURL = socialData.getProperty(prefix + "userinfo_url"); String socialBeanProps = socialData.getProperty(prefix + "beanProps"); @@ -777,7 +797,7 @@ public Response userinfoGeneric(@PathParam("provider") String provider, @Context String accessString = null; try { - AccessToken genericToken = semossUser.getAvailableAccessToken(providerEnum); + AccessToken genericToken = semossUser.getAccessToken(providerEnum); accessString = genericToken.getAccess_token(); // String url = "https://graph.microsoft.com/v1.0/me/"; String output = HttpHelperUtility.makeGetCall(userInfoURL, accessString, null, true); @@ -812,6 +832,12 @@ public Response userinfoGeneric(@PathParam("provider") String provider, @Context @Path("/login/salesforce") public Response loginSalesforce(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { + if (socialData.getLoginsAllowed().get("salesforce") == null + || !socialData.getLoginsAllowed().get("salesforce")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Salesforce login is not allowed"); + return WebUtility.getResponse(ret, 400); + } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -821,22 +847,6 @@ public Response loginSalesforce(@Context HttpServletRequest request, @Context Ht if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get("salesforce") == null - || !socialData.getConnectionsAllowed().get("salesforce")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Salesforce resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get("salesforce") == null || !socialData.getLoginsAllowed().get("salesforce")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Salesforce login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -846,7 +856,7 @@ public Response loginSalesforce(@Context HttpServletRequest request, @Context Ht } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.SALESFORCE) == null && userObj.getResourceAccessToken(AuthProvider.SALESFORCE) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.SALESFORCE) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -880,12 +890,8 @@ public Response loginSalesforce(@Context HttpServletRequest request, @Context Ht return null; } accessToken.setProvider(AuthProvider.SALESFORCE); - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } + addAccessToken(accessToken, request, autoAdd); + if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); } @@ -897,13 +903,13 @@ public Response loginSalesforce(@Context HttpServletRequest request, @Context Ht if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.SALESFORCE) == null && userObj.getResourceAccessToken(AuthProvider.SALESFORCE) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.SALESFORCE) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getSalesforceRedirect(request)); return null; } - + setMainPageRedirect(request, response); return null; } @@ -922,7 +928,6 @@ private String getSalesforceRedirect(HttpServletRequest request) throws Unsuppor return redirectUrl; } - /** * Logs user in through survey monkey */ @@ -931,6 +936,12 @@ private String getSalesforceRedirect(HttpServletRequest request) throws Unsuppor @Path("/login/surveymonkey") public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { + if (socialData.getLoginsAllowed().get("surveymonkey") == null + || !socialData.getLoginsAllowed().get("surveymonkey")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Surveymonkey login is not allowed"); + return WebUtility.getResponse(ret, 400); + } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -940,23 +951,6 @@ public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get("surveymonkey") == null - || !socialData.getConnectionsAllowed().get("surveymonkey")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "surveymonkey resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get("surveymonkey") == null - || !socialData.getLoginsAllowed().get("surveymonkey")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "surveymonkey login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -966,7 +960,7 @@ public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null && userObj.getResourceAccessToken(AuthProvider.SURVEYMONKEY) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1001,12 +995,7 @@ public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context } accessToken.setProvider(AuthProvider.SURVEYMONKEY); MonkeyProfile.fillAccessToken(accessToken, null); - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } + addAccessToken(accessToken, request, autoAdd); if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -1019,13 +1008,13 @@ public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null && userObj.getResourceAccessToken(AuthProvider.SURVEYMONKEY) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.SURVEYMONKEY) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getSurveyMonkeyRedirect(request)); return null; } - + setMainPageRedirect(request, response); return null; } @@ -1053,6 +1042,11 @@ private String getSurveyMonkeyRedirect(HttpServletRequest request) throws Unsupp @Path("/login/github") public Response loginGithub(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { + if (socialData.getLoginsAllowed().get("github") == null || !socialData.getLoginsAllowed().get("github")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "GitHub login is not allowed"); + return WebUtility.getResponse(ret, 400); + } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -1062,22 +1056,6 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get("github") == null - || !socialData.getConnectionsAllowed().get("github")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Github resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get("github") == null || !socialData.getLoginsAllowed().get("github")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Github login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1088,7 +1066,7 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.GITHUB) == null && userObj.getResourceAccessToken(AuthProvider.GITHUB) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.GITHUB) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code and state should match [ -~]+ (1 or more ascii) @@ -1124,6 +1102,7 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe return null; } accessToken.setProvider(AuthProvider.GITHUB); + try { GitRepoUtils.addCertForDomain(url); } catch (Exception e) { @@ -1132,12 +1111,9 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe // add specific Git values GithubTokenFiller profiler = new GithubTokenFiller(); profiler.fillAccessToken(accessToken, null, null, null, null); - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } + + addAccessToken(accessToken, request, autoAdd); + if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); } @@ -1149,7 +1125,7 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.GITHUB) == null && userObj.getResourceAccessToken(AuthProvider.GITHUB) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.GITHUB) == null) { // not authenticated try { GitRepoUtils.addCertForDomain("https://github.com"); @@ -1160,7 +1136,7 @@ public Response loginGithub(@Context HttpServletRequest request, @Context HttpSe response.sendRedirect(getGithubRedirect(request)); return null; } - + setMainPageRedirect(request, response); return null; } @@ -1180,7 +1156,7 @@ private String getGithubRedirect(HttpServletRequest request) throws UnsupportedE } return redirectUrl; } - + /** * Logs user in through gitlab * https://docs.gitlab.com/13.12/ee/integration/oauth_provider.html @@ -1191,6 +1167,11 @@ private String getGithubRedirect(HttpServletRequest request) throws UnsupportedE @Path("/login/gitlab") public Response loginGitlab(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { + if (socialData.getLoginsAllowed().get("gitlab") == null || !socialData.getLoginsAllowed().get("gitlab")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "GitLab login is not allowed"); + return WebUtility.getResponse(ret, 400); + } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -1200,22 +1181,6 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get("gitlab") == null - || !socialData.getConnectionsAllowed().get("gitlab")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Gitlab resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get("gitlab") == null || !socialData.getLoginsAllowed().get("gitlab")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Gitlab login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1228,7 +1193,7 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe String prefix = "gitlab_"; if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.GITLAB) == null && userObj.getResourceAccessToken(AuthProvider.GITLAB) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.GITLAB) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code and state should match [ -~]+ (1 or more ascii) @@ -1273,12 +1238,7 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe true); accessToken = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanPropsArr, accessToken); - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } + addAccessToken(accessToken, request, autoAdd); if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -1291,7 +1251,7 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.GITLAB) == null && userObj.getResourceAccessToken(AuthProvider.GITLAB) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.GITLAB) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getGitlabRedirect(request)); @@ -1302,7 +1262,7 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe // get groups String group_url = socialData.getProperty(prefix + "group_url"); String groupsJson = HttpHelperUtility.makeGetCall(group_url, - userObj.getAvailableAccessToken(AuthProvider.GITLAB).getAccess_token()); + userObj.getAccessToken(AuthProvider.GITLAB).getAccess_token()); System.out.println(groupsJson); String groupJsonPattern = socialData.getProperty(prefix + "groupJsonPattern"); // String beanProps = socialData.getProperty(prefix + "groupBeanProps"); @@ -1318,10 +1278,10 @@ public Response loginGitlab(@Context HttpServletRequest request, @Context HttpSe userGroups.add(thisInput); } - userObj.getAvailableAccessToken(AuthProvider.GITLAB).setUserGroups(userGroups); - userObj.getAvailableAccessToken(AuthProvider.GITLAB).setUserGroupType(AuthProvider.GITLAB.toString()); + userObj.getAccessToken(AuthProvider.GITLAB).setUserGroups(userGroups); + userObj.getAccessToken(AuthProvider.GITLAB).setUserGroupType(AuthProvider.GITLAB.toString()); } - + setMainPageRedirect(request, response); return null; } @@ -1346,7 +1306,7 @@ private String getGitlabRedirect(HttpServletRequest request) throws UnsupportedE } return redirectUrl; } - + /** * Logs user in through ms */ @@ -1364,6 +1324,11 @@ public Response loginMS(@Context HttpServletRequest request, @Context HttpServle @Path("/login/microsoft") public Response loginMicrosoft(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { + if (socialData.getLoginsAllowed().get("ms") == null || !socialData.getLoginsAllowed().get("ms")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Microsoft login is not allowed"); + return WebUtility.getResponse(ret, 400); + } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -1373,21 +1338,6 @@ public Response loginMicrosoft(@Context HttpServletRequest request, @Context Htt if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get("ms") == null || !socialData.getConnectionsAllowed().get("ms")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Microsoft resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get("ms") == null || !socialData.getLoginsAllowed().get("ms")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Microsoft login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1397,7 +1347,7 @@ public Response loginMicrosoft(@Context HttpServletRequest request, @Context Htt } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.MICROSOFT) == null && userObj.getResourceAccessToken(AuthProvider.MICROSOFT) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.MICROSOFT) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1448,12 +1398,7 @@ public Response loginMicrosoft(@Context HttpServletRequest request, @Context Htt throw new IllegalArgumentException("External users are not allowed"); } } - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } + addAccessToken(accessToken, request, autoAdd); if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -1466,13 +1411,13 @@ public Response loginMicrosoft(@Context HttpServletRequest request, @Context Htt if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.MICROSOFT) == null && userObj.getResourceAccessToken(AuthProvider.MICROSOFT) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.MICROSOFT) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getMicrosoftRedirect(request)); return null; } - + setMainPageRedirect(request, response); return null; } @@ -1500,7 +1445,7 @@ private String getMicrosoftRedirect(HttpServletRequest request) throws Unsupport return redirectUrl; } - + /** * Logs user in through adfs */ @@ -1509,6 +1454,11 @@ private String getMicrosoftRedirect(HttpServletRequest request) throws Unsupport @Path("/login/adfs") public Response loginADFS(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { + if (socialData.getLoginsAllowed().get("adfs") == null || !socialData.getLoginsAllowed().get("adfs")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "ADFS login is not allowed"); + return WebUtility.getResponse(ret, 400); + } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -1518,22 +1468,6 @@ public Response loginADFS(@Context HttpServletRequest request, @Context HttpServ if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get("adfs") == null - || !socialData.getConnectionsAllowed().get("adfs")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "adfs resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get("adfs") == null || !socialData.getLoginsAllowed().get("adfs")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "adfs login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1544,7 +1478,7 @@ public Response loginADFS(@Context HttpServletRequest request, @Context HttpServ String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.ADFS) == null && userObj.getResourceAccessToken(AuthProvider.ADFS) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.ADFS) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1590,12 +1524,7 @@ public Response loginADFS(@Context HttpServletRequest request, @Context HttpServ String[] beanPropsArr = beanProps.split(",", -1); accessToken = (AccessToken) BeanFiller.fillFromJson(json, jsonPattern, beanPropsArr, accessToken); - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } + addAccessToken(accessToken, request, autoAdd); if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -1608,13 +1537,13 @@ public Response loginADFS(@Context HttpServletRequest request, @Context HttpServ if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.ADFS) == null && userObj.getResourceAccessToken(AuthProvider.ADFS) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.ADFS) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getADFSRedirect(request)); return null; } - + setMainPageRedirect(request, response); return null; } @@ -1666,6 +1595,11 @@ private String getADFSRedirect(HttpServletRequest request) throws UnsupportedEnc @Path("/login/okta") public Response loginOkta(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { + if (socialData.getLoginsAllowed().get("okta") == null || !socialData.getLoginsAllowed().get("okta")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Okta login is not allowed"); + return WebUtility.getResponse(ret, 400); + } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -1675,22 +1609,6 @@ public Response loginOkta(@Context HttpServletRequest request, @Context HttpServ if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get("okta") == null - || !socialData.getConnectionsAllowed().get("okta")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "okta resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get("okta") == null || !socialData.getLoginsAllowed().get("okta")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "okta login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1700,7 +1618,7 @@ public Response loginOkta(@Context HttpServletRequest request, @Context HttpServ } String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.OKTA) == null && userObj.getResourceAccessToken(AuthProvider.OKTA) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.MICROSOFT) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1745,12 +1663,7 @@ public Response loginOkta(@Context HttpServletRequest request, @Context HttpServ OktaTokenFiller profiler = new OktaTokenFiller(); profiler.fillAccessToken(accessToken, userinfo_url, jsonPattern, beanPropsArr, null); - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } + addAccessToken(accessToken, request, autoAdd); if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); } @@ -1762,13 +1675,13 @@ public Response loginOkta(@Context HttpServletRequest request, @Context HttpServ if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.OKTA) == null && userObj.getResourceAccessToken(AuthProvider.OKTA) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.OKTA) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getOktaRedirect(request)); return null; } - + setMainPageRedirect(request, response); return null; } @@ -1800,6 +1713,12 @@ private String getOktaRedirect(HttpServletRequest request) throws UnsupportedEnc @Path("/login/siteminder") public Response loginSiteminder(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { + if (socialData.getLoginsAllowed().get("siteminder") == null + || !socialData.getLoginsAllowed().get("siteminder")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Siteminder login is not allowed"); + return WebUtility.getResponse(ret, 400); + } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -1809,23 +1728,6 @@ public Response loginSiteminder(@Context HttpServletRequest request, @Context Ht if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get("siteminder") == null - || !socialData.getConnectionsAllowed().get("siteminder")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "siteminder resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get("siteminder") == null - || !socialData.getLoginsAllowed().get("siteminder")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "siteminder login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1836,7 +1738,7 @@ public Response loginSiteminder(@Context HttpServletRequest request, @Context Ht String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.SITEMINDER) == null && userObj.getResourceAccessToken(AuthProvider.SITEMINDER) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.SITEMINDER) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1876,12 +1778,7 @@ public Response loginSiteminder(@Context HttpServletRequest request, @Context Ht } accessToken.setProvider(AuthProvider.SITEMINDER); - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } + addAccessToken(accessToken, request, autoAdd); if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); } @@ -1893,13 +1790,13 @@ public Response loginSiteminder(@Context HttpServletRequest request, @Context Ht if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.SITEMINDER) == null && userObj.getResourceAccessToken(AuthProvider.SITEMINDER) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.SITEMINDER) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getSiteminderRedirect(request)); return null; } - + setMainPageRedirect(request, response); return null; } @@ -1936,6 +1833,11 @@ private String getSiteminderRedirect(HttpServletRequest request) throws Unsuppor @Path("/login/dropbox") public Response loginDropBox(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { + if (socialData.getLoginsAllowed().get("dropbox") == null || !socialData.getLoginsAllowed().get("dropbox")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Dropbox login is not allowed"); + return WebUtility.getResponse(ret, 400); + } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -1945,22 +1847,6 @@ public Response loginDropBox(@Context HttpServletRequest request, @Context HttpS if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get("dropbox") == null - || !socialData.getConnectionsAllowed().get("dropbox")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "dropbox resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get("dropbox") == null || !socialData.getLoginsAllowed().get("dropbox")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "dropbox login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1971,7 +1857,7 @@ public Response loginDropBox(@Context HttpServletRequest request, @Context HttpS String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.DROPBOX) == null && userObj.getResourceAccessToken(AuthProvider.DROPBOX) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.DROPBOX) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2005,12 +1891,7 @@ public Response loginDropBox(@Context HttpServletRequest request, @Context HttpS return null; } accessToken.setProvider(AuthProvider.DROPBOX); - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } + addAccessToken(accessToken, request, autoAdd); if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -2023,13 +1904,13 @@ public Response loginDropBox(@Context HttpServletRequest request, @Context HttpS if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.DROPBOX) == null && userObj.getResourceAccessToken(AuthProvider.DROPBOX) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.DROPBOX) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getDBRedirect(request)); return null; } - + setMainPageRedirect(request, response); return null; } @@ -2052,7 +1933,7 @@ private String getDBRedirect(HttpServletRequest request) throws UnsupportedEncod } /** - * Logs user in through google + * Logs user in through google or connects google for resource access * https://developers.google.com/api-client-library/java/google-api-java-client/oauth2 */ @GET @@ -2060,31 +1941,43 @@ private String getDBRedirect(HttpServletRequest request) throws UnsupportedEncod @Path("/login/google") public Response loginGoogle(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { + boolean loginAllowed = socialData.getLoginsAllowed().get("google") != null + && socialData.getLoginsAllowed().get("google"); + boolean connectAllowed = socialData.getConnectionsAllowed().get("google") != null + && socialData.getConnectionsAllowed().get("google"); + + if (!loginAllowed && !connectAllowed) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Google login/connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } /* - * Try to log in the user If they are not logged in Redirect the FE + * Determine operation type: login vs connect - Login: User has no existing + * session or no existing logins - Connect: User is already logged in with + * another provider and wants to add Google for resource access */ - HttpSession session = request.getSession(false); User userObj = null; if (session != null) { - userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); + userObj = (User) session.getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get("google") == null || !socialData.getConnectionsAllowed().get("google")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Google resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get("google") == null || !socialData.getLoginsAllowed().get("google")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Google login is not allowed"); - return WebUtility.getResponse(ret, 400); - } + // check if user is already logged in + boolean userAlreadyLoggedIn = userObj != null && !userObj.getLogins().isEmpty(); + // if user is already logged in, and connect is allowed, then it's a connect + // operation + boolean isConnectOperation = userAlreadyLoggedIn && connectAllowed; + + // Validate the operation is allowed based on user state + if (!userAlreadyLoggedIn && !loginAllowed) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Google login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + if (userAlreadyLoggedIn && !connectAllowed) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Google connection is not allowed"); + return WebUtility.getResponse(ret, 400); } - String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -2095,7 +1988,18 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.GOOGLE) == null && userObj.getResourceAccessToken(AuthProvider.GOOGLE) == null)) { + // Determine if we need to process the OAuth code + // For connect operation: userObj is guaranteed non-null due to earlier check + // For login operation: userObj might be null + boolean needsProcessing; + if (isConnectOperation) { + // userObj is guaranteed non-null here + needsProcessing = userObj.getResourceAccessToken(AuthProvider.GOOGLE) == null; + } else { + // need to check if userObj is null + needsProcessing = (userObj == null || userObj.getAccessToken(AuthProvider.GOOGLE) == null); + } + if (needsProcessing) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2109,7 +2013,8 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); if (classLogger.isDebugEnabled()) { - classLogger.debug(">> " + Utility.cleanLogString(request.getQueryString())); + classLogger.debug( + "Processing Google OAuth code for " + (isConnectOperation ? "connection" : "login")); } // I need to decode the return code from google since the default param's are @@ -2123,29 +2028,40 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe String url = "https://www.googleapis.com/oauth2/v4/token"; - // https://developers.google.com/api-client-library/java/google-api-java-client/oauth2 - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getGoogleRedirect(request)); - return null; - } - accessToken.setProvider(AuthProvider.GOOGLE); + try { + // https://developers.google.com/api-client-library/java/google-api-java-client/oauth2 + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); + if (accessToken == null) { + classLogger.error("Failed to obtain access token from Google"); + // Redirect back to start OAuth flow again + response.setStatus(302); + response.sendRedirect(getGoogleRedirect(request)); + return null; + } + accessToken.setProvider(AuthProvider.GOOGLE); - // fill the access token with the other properties so we can properly create the - // user - GoogleTokenFiller profiler = new GoogleTokenFiller(); - profiler.fillAccessToken(accessToken, null, null, null, null); - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } - // Shows how to make a google credential from an access token - if (classLogger.isDebugEnabled()) { - classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); + // Fill the access token with user profile information + GoogleTokenFiller profiler = new GoogleTokenFiller(); + profiler.fillAccessToken(accessToken, null, null, null, null); + + if (isConnectOperation) { + // User is already logged in, add as resource access token for data integration + addResourceAccessToken(accessToken, request, autoAdd); + classLogger.info("User connected Google account for resource access"); + } else { + // User is not logged in, add as login access token + addAccessToken(accessToken, request, autoAdd); + classLogger.info("User logged in with Google"); + } + + if (classLogger.isDebugEnabled()) { + classLogger.debug("Successfully processed Google OAuth token"); + } + } catch (Exception e) { + classLogger.error("Error during Google OAuth token exchange", e); + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Failed to authenticate with Google: " + e.getMessage()); + return WebUtility.getResponse(ret, 500); } } } @@ -2155,13 +2071,25 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.GOOGLE) == null && userObj.getResourceAccessToken(AuthProvider.GOOGLE) == null)) { - // not authenticated + + // Check authentication status based on operation type + boolean isAuthenticated; + if (isConnectOperation) { + // For connect operations, userObj should never be null at this point + // but check defensively + isAuthenticated = (userObj != null && userObj.getResourceAccessToken(AuthProvider.GOOGLE) != null); + } else { + // For login operations + isAuthenticated = (userObj != null && userObj.getAccessToken(AuthProvider.GOOGLE) != null); + } + + if (!isAuthenticated) { + // Not authenticated/connected yet, redirect to start OAuth flow response.setStatus(302); response.sendRedirect(getGoogleRedirect(request)); return null; } - + setMainPageRedirect(request, response); return null; } @@ -2247,6 +2175,12 @@ private String getGoogleRedirect(HttpServletRequest request) throws UnsupportedE @Path("/login/producthunt") public Response loginProducthunt(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { + if (socialData.getLoginsAllowed().get("producthunt") == null + || !socialData.getLoginsAllowed().get("producthunt")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Producthunt login is not allowed"); + return WebUtility.getResponse(ret, 400); + } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -2256,23 +2190,6 @@ public Response loginProducthunt(@Context HttpServletRequest request, @Context H if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get("producthunt") == null - || !socialData.getConnectionsAllowed().get("producthunt")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "producthunt resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get("producthunt") == null - || !socialData.getLoginsAllowed().get("producthunt")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "producthunt login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -2283,7 +2200,7 @@ public Response loginProducthunt(@Context HttpServletRequest request, @Context H String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null && userObj.getResourceAccessToken(AuthProvider.PRODUCT_HUNT) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2317,12 +2234,7 @@ public Response loginProducthunt(@Context HttpServletRequest request, @Context H return null; } accessToken.setProvider(AuthProvider.PRODUCT_HUNT); - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } + addAccessToken(accessToken, request, autoAdd); if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -2335,12 +2247,12 @@ public Response loginProducthunt(@Context HttpServletRequest request, @Context H if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null && userObj.getResourceAccessToken(AuthProvider.PRODUCT_HUNT) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.PRODUCT_HUNT) == null) { response.setStatus(302); response.sendRedirect(getProducthuntRedirect(request)); return null; } - + setMainPageRedirect(request, response); return null; } @@ -2371,6 +2283,11 @@ private String getProducthuntRedirect(HttpServletRequest request) throws Unsuppo @Path("/login/linkedin") public Response loginLinkedin(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { + if (socialData.getLoginsAllowed().get("linkedin") == null || !socialData.getLoginsAllowed().get("linkedin")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "LinkedIn login is not allowed"); + return WebUtility.getResponse(ret, 400); + } /* * Try to log in the user If they are not logged in Redirect the FE */ @@ -2380,23 +2297,6 @@ public Response loginLinkedin(@Context HttpServletRequest request, @Context Http if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get("linkedin") == null - || !socialData.getConnectionsAllowed().get("linkedin")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "linkedin resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get("linkedin") == null - || !socialData.getLoginsAllowed().get("linkedin")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "linkedin login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -2407,7 +2307,7 @@ public Response loginLinkedin(@Context HttpServletRequest request, @Context Http String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.LINKEDIN) == null && userObj.getResourceAccessToken(AuthProvider.LINKEDIN) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.LINKEDIN) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2441,12 +2341,7 @@ public Response loginLinkedin(@Context HttpServletRequest request, @Context Http return null; } accessToken.setProvider(AuthProvider.LINKEDIN); - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } + addAccessToken(accessToken, request, autoAdd); if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -2459,12 +2354,12 @@ public Response loginLinkedin(@Context HttpServletRequest request, @Context Http if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.LINKEDIN) == null && userObj.getResourceAccessToken(AuthProvider.LINKEDIN) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.LINKEDIN) == null) { response.setStatus(302); response.sendRedirect(getLinkedinRedirect(request)); return null; } - + setMainPageRedirect(request, response); return null; } @@ -2499,6 +2394,11 @@ private String getLinkedinRedirect(HttpServletRequest request) throws Unsupporte @Path("/login/twitter") public Response loginTwitter(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { + if (socialData.getLoginsAllowed().get("twitter") == null || !socialData.getLoginsAllowed().get("twitter")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Twitter login is not allowed"); + return WebUtility.getResponse(ret, 400); + } // getting the bearer token on twitter for app authentication is a lot simpler // need to just combine the id and secret // base 64 and send as authorization @@ -2510,23 +2410,6 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get("twitter") == null - || !socialData.getConnectionsAllowed().get("twitter")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "twitter resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get("twitter") == null - || !socialData.getLoginsAllowed().get("twitter")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "twitter login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -2537,7 +2420,7 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(AuthProvider.TWITTER) == null && userObj.getResourceAccessToken(AuthProvider.TWITTER) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.GITHUB) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code and state should match [ -~]+ (1 or more ascii) @@ -2574,12 +2457,7 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS } accessToken.setProvider(AuthProvider.TWITTER); - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } + addAccessToken(accessToken, request, autoAdd); if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -2592,13 +2470,13 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(AuthProvider.TWITTER) == null && userObj.getResourceAccessToken(AuthProvider.TWITTER) == null)) { + if (userObj == null || userObj.getAccessToken(AuthProvider.TWITTER) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getTwitterRedirect(request)); return null; } - + setMainPageRedirect(request, response); return null; } @@ -2650,6 +2528,11 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht */ provider = WebUtility.inputSanitizer(provider); + if (socialData.getLoginsAllowed().get(provider) == null || !socialData.getLoginsAllowed().get(provider)) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, provider + " login is not allowed"); + return WebUtility.getResponse(ret, 400); + } AuthProvider providerEnum = AuthProvider.getProviderFromString(provider.toUpperCase()); @@ -2658,23 +2541,6 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht if (session != null) { userObj = (User) request.getSession().getAttribute(Constants.SESSION_USER); } - boolean isResourceConnection = (userObj != null); - - if (isResourceConnection) { - if (socialData.getConnectionsAllowed().get(provider) == null - || !socialData.getConnectionsAllowed().get(provider)) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "twitter resource connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } else { - if (socialData.getLoginsAllowed().get(provider) == null - || !socialData.getLoginsAllowed().get(provider)) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "twitter login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - } String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -2685,7 +2551,7 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - if (userObj == null || (userObj.getAccessToken(providerEnum) == null && userObj.getResourceAccessToken(providerEnum) == null)) { + if (userObj == null || userObj.getAccessToken(providerEnum) == null) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -2812,12 +2678,7 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht accessToken.setUserGroupType(providerEnum.toString()); } - // add to specific access token based on the isResourceConnection value - if (isResourceConnection) { - addResourceAccessToken(accessToken, request, autoAdd); - } else { - addAccessToken(accessToken, request, autoAdd); - } + addAccessToken(accessToken, request, autoAdd); if (classLogger.isDebugEnabled()) { classLogger.debug("Access Token is.. " + accessToken.getAccess_token()); @@ -2830,13 +2691,13 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (userObj == null || (userObj.getAccessToken(providerEnum) == null && userObj.getResourceAccessToken(providerEnum) == null)) { + if (userObj == null || userObj.getAccessToken(providerEnum) == null) { // not authenticated response.setStatus(302); response.sendRedirect(getGenericRedirect(provider, request)); return null; } - + setMainPageRedirect(request, response); return null; } @@ -2875,6 +2736,7 @@ private String getGenericRedirect(String provider, HttpServletRequest request) t return redirectUrl; } + // public static String calculateRFC2104HMAC(String data, String key) throws // SignatureException, NoSuchAlgorithmException, InvalidKeyException { // SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1"); @@ -3586,7 +3448,7 @@ public Response show(@Context HttpServletRequest request, @Context HttpServletRe if (session != null) { User user = (User) session.getAttribute(Constants.SESSION_USER); if (user != null) { - AccessToken token = user.getResourceAccessToken(user.getPrimaryLogin()); + AccessToken token = user.getAccessToken(user.getPrimaryLogin()); output.put("name", token.getId()); output.put("warning", "null principal - grab from user"); } From 58c796add4cac6bb4f862f350dc1bb23d191ce8e Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 Date: Mon, 9 Feb 2026 14:02:17 +0530 Subject: [PATCH 10/20] fix: updated code based on pr review comments --- .../config/ServerConfigurationResource.java | 44 ++++---- .../web/services/local/ResourceUtility.java | 2 - .../web/services/local/UserResource.java | 100 +++++++----------- 3 files changed, 60 insertions(+), 86 deletions(-) diff --git a/src/prerna/semoss/web/services/config/ServerConfigurationResource.java b/src/prerna/semoss/web/services/config/ServerConfigurationResource.java index afdc8ddd7..182819404 100644 --- a/src/prerna/semoss/web/services/config/ServerConfigurationResource.java +++ b/src/prerna/semoss/web/services/config/ServerConfigurationResource.java @@ -244,28 +244,28 @@ private static void loadConfig() { private static Map getConfiguration(@Context HttpServletRequest request, User user) { HttpSession session = request.getSession(); - Map myConfiguration = new HashMap<>(); - myConfiguration.putAll(config); + Map clientConfig = new HashMap<>(); + clientConfig.putAll(config); // session timeout // in case we have different timeout for the admin // we have this grab for this session what the timeout value is - myConfiguration.put("timeout", (double) session.getMaxInactiveInterval() / 60); + clientConfig.put("timeout", (double) session.getMaxInactiveInterval() / 60); // append values that can change without restarting the server // logins allowed - myConfiguration.put("loginsAllowed", SocialPropertiesUtil.getInstance().getLoginsAllowed()); + clientConfig.put("loginsAllowed", SocialPropertiesUtil.getInstance().getLoginsAllowed()); // connections allowed - myConfiguration.put("connectionsAllowed", SocialPropertiesUtil.getInstance().getConnectionsAllowed()); + clientConfig.put("connectionsAllowed", SocialPropertiesUtil.getInstance().getConnectionsAllowed()); // get a list of all the logins and the display name and if it is oauth - myConfiguration.put("availableProviders", SocialPropertiesUtil.getInstance().getAvailableProviders()); + clientConfig.put("availableProviders", SocialPropertiesUtil.getInstance().getAvailableProviders()); // get a list of all the resource providers and the display name if it is oauth - myConfiguration.put("availableResourceProviders", SocialPropertiesUtil.getInstance().getAvailableResourceProviders()); + clientConfig.put("availableResourceProviders", + SocialPropertiesUtil.getInstance().getAvailableResourceProviders()); // is native registration allowed - myConfiguration.put("nativeRegistration", SocialPropertiesUtil.getInstance().isNativeRegistrationAllowed()); + clientConfig.put("nativeRegistration", SocialPropertiesUtil.getInstance().isNativeRegistrationAllowed()); // password requirements try { - myConfiguration.put("passwordRequirements", - PasswordRequirements.getInstance().getAllPasswordRequirements()); + clientConfig.put("passwordRequirements", PasswordRequirements.getInstance().getAllPasswordRequirements()); } catch (Exception e) { classLogger.error(Constants.STACKTRACE, e); } @@ -274,29 +274,29 @@ private static Map getConfiguration(@Context HttpServletRequest // TODO: should move away from logins cause sometimes people are using this as // if the name is the ID // TODO: but not sure where this is all happening, so sending both keys for now - myConfiguration.put("logins", User.getLoginNames(user)); - myConfiguration.put("loginDetails", User.getLoginDetails(user)); + clientConfig.put("logins", User.getLoginNames(user)); + clientConfig.put("loginDetails", User.getLoginDetails(user)); // current resource connections - myConfiguration.put("connections", User.getConnectionsNames(user)); - myConfiguration.put("connectionDetails", User.getConnectionDetails(user)); + clientConfig.put("connections", User.getConnectionsNames(user)); + clientConfig.put("connectionDetails", User.getConnectionDetails(user)); // themes - myConfiguration.put("theme", AdminThemeUtils.getActiveAdminTheme()); + clientConfig.put("theme", AdminThemeUtils.getActiveAdminTheme()); // add if we are using csrf - myConfiguration.put("csrf", Boolean.parseBoolean(session.getAttribute("csrf") + "")); + clientConfig.put("csrf", Boolean.parseBoolean(session.getAttribute("csrf") + "")); // add metakey options - myConfiguration.put("databaseMetaKeys", SecurityEngineUtils.getMetakeyOptions(null)); - myConfiguration.put("engineMetaKeys", SecurityEngineUtils.getMetakeyOptions(null)); - myConfiguration.put("projectMetaKeys", SecurityProjectUtils.getMetakeyOptions(null)); - myConfiguration.put("insightMetaKeys", SecurityInsightUtils.getMetakeyOptions(null)); + clientConfig.put("databaseMetaKeys", SecurityEngineUtils.getMetakeyOptions(null)); + clientConfig.put("engineMetaKeys", SecurityEngineUtils.getMetakeyOptions(null)); + clientConfig.put("projectMetaKeys", SecurityProjectUtils.getMetakeyOptions(null)); + clientConfig.put("insightMetaKeys", SecurityInsightUtils.getMetakeyOptions(null)); // current date - myConfiguration.put("systemDate", new SemossDate(Utility.getCurrentZonedDateTimeUTC())); + clientConfig.put("systemDate", new SemossDate(Utility.getCurrentZonedDateTimeUTC())); // do not keep this session // if no user and it is new if (user == null && (session.isNew() || request.isRequestedSessionIdValid())) { session.invalidate(); } - return myConfiguration; + return clientConfig; } @GET diff --git a/src/prerna/semoss/web/services/local/ResourceUtility.java b/src/prerna/semoss/web/services/local/ResourceUtility.java index ded45f7b8..0a7b79a32 100644 --- a/src/prerna/semoss/web/services/local/ResourceUtility.java +++ b/src/prerna/semoss/web/services/local/ResourceUtility.java @@ -63,8 +63,6 @@ public class ResourceUtility { allowAccessWithoutLogin.add("config/fetchCsrf"); allowAccessWithoutLogin.add("auth/logins"); allowAccessWithoutLogin.add("auth/loginsAllowed"); - allowAccessWithoutLogin.add("auth/connections"); - allowAccessWithoutLogin.add("auth/connectionsAllowed"); allowAccessWithoutLogin.add("auth/login"); allowAccessWithoutLogin.add("auth/loginLDAP"); allowAccessWithoutLogin.add("auth/changeADPassword"); diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index 571e2bd00..021d2f9db 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -387,12 +387,15 @@ public static void addAccessToken(AccessToken token, HttpServletRequest request, * @param token * @param request */ - public static void addResourceAccessToken(AccessToken token, HttpServletRequest request, boolean autoAdd) { + public static void addResourceAccessToken(AccessToken token, HttpServletRequest request) { HttpSession session = request.getSession(); User semossUser = (User) session.getAttribute(Constants.SESSION_USER); - if (autoAdd) { - SecurityUpdateUtils.addOAuthUser(token); + if (semossUser == null) { + classLogger.error("No user found in session when trying to add resource access token"); + return; } + + // add new resource access token to the user semossUser.setResourceAccessToken(token); semossUser.setAnonymous(false); session.setAttribute(Constants.SESSION_USER, semossUser); @@ -1932,6 +1935,7 @@ private String getDBRedirect(HttpServletRequest request) throws UnsupportedEncod return redirectUrl; } + /** * Logs user in through google or connects google for resource access * https://developers.google.com/api-client-library/java/google-api-java-client/oauth2 @@ -1946,38 +1950,31 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe boolean connectAllowed = socialData.getConnectionsAllowed().get("google") != null && socialData.getConnectionsAllowed().get("google"); + // At least one operation must be allowed login/connect if (!loginAllowed && !connectAllowed) { Map ret = new HashMap<>(); ret.put(Constants.ERROR_MESSAGE, "Google login/connection is not allowed"); return WebUtility.getResponse(ret, 400); } - /* - * Determine operation type: login vs connect - Login: User has no existing - * session or no existing logins - Connect: User is already logged in with - * another provider and wants to add Google for resource access - */ + + // Determine operation type based on flag values + boolean isLoginOperation = loginAllowed; + boolean isConnectOperation = connectAllowed; + + // For connect operations, user must already be logged in HttpSession session = request.getSession(false); User userObj = null; if (session != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - // check if user is already logged in - boolean userAlreadyLoggedIn = userObj != null && !userObj.getLogins().isEmpty(); - // if user is already logged in, and connect is allowed, then it's a connect - // operation - boolean isConnectOperation = userAlreadyLoggedIn && connectAllowed; - - // Validate the operation is allowed based on user state - if (!userAlreadyLoggedIn && !loginAllowed) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Google login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - if (userAlreadyLoggedIn && !connectAllowed) { + + // A user must be already logged in before we can connect + if (isConnectOperation && (userObj == null || userObj.getLogins().isEmpty())) { Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Google connection is not allowed"); - return WebUtility.getResponse(ret, 400); + ret.put(Constants.ERROR_MESSAGE, "User must be logged in to connect Google account"); + return WebUtility.getResponse(ret, 401); } + String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); if (customRedirect != null && !customRedirect.isEmpty()) { if (session == null) { @@ -1985,26 +1982,19 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe } session.setAttribute(CUSTOM_REDIRECT_SESSION_KEY, customRedirect); } + + boolean loginComplete = (userObj != null && userObj.getAccessToken(AuthProvider.GOOGLE) != null); + boolean connectComplete = (userObj != null && userObj.getResourceAccessToken(AuthProvider.GOOGLE) != null); + // Process OAuth callback if code is present String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); if (queryString != null && queryString.contains("code")) { - // Determine if we need to process the OAuth code - // For connect operation: userObj is guaranteed non-null due to earlier check - // For login operation: userObj might be null - boolean needsProcessing; - if (isConnectOperation) { - // userObj is guaranteed non-null here - needsProcessing = userObj.getResourceAccessToken(AuthProvider.GOOGLE) == null; - } else { - // need to check if userObj is null - needsProcessing = (userObj == null || userObj.getAccessToken(AuthProvider.GOOGLE) == null); - } - if (needsProcessing) { + if (!loginComplete || !connectComplete) { String[] outputs = HttpHelperUtility.getCodes(queryString); + String code = URLDecoder.decode(outputs[0]); // oauth code should match [ -~]+ (1 or more ascii) // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0]); if (code.matches("[ -~]+")) { String prefix = "google_"; String clientId = socialData.getProperty(prefix + "client_id"); @@ -2013,12 +2003,9 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); if (classLogger.isDebugEnabled()) { - classLogger.debug( - "Processing Google OAuth code for " + (isConnectOperation ? "connection" : "login")); + classLogger.debug(">> " + Utility.cleanLogString(request.getQueryString())); } - // I need to decode the return code from google since the default param's are - // encoded on the post of getAccessToken Map params = new HashMap<>(); params.put("client_id", clientId); params.put("redirect_uri", redirectUri); @@ -2029,11 +2016,10 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe String url = "https://www.googleapis.com/oauth2/v4/token"; try { - // https://developers.google.com/api-client-library/java/google-api-java-client/oauth2 + // Get access token from Google (same for both operations) AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); if (accessToken == null) { classLogger.error("Failed to obtain access token from Google"); - // Redirect back to start OAuth flow again response.setStatus(302); response.sendRedirect(getGoogleRedirect(request)); return null; @@ -2044,16 +2030,17 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe GoogleTokenFiller profiler = new GoogleTokenFiller(); profiler.fillAccessToken(accessToken, null, null, null, null); - if (isConnectOperation) { - // User is already logged in, add as resource access token for data integration - addResourceAccessToken(accessToken, request, autoAdd); - classLogger.info("User connected Google account for resource access"); - } else { - // User is not logged in, add as login access token + // Add token based on which operations are allowed + if (isLoginOperation) { addAccessToken(accessToken, request, autoAdd); classLogger.info("User logged in with Google"); } + if (isConnectOperation) { + addResourceAccessToken(accessToken, request); + classLogger.info("User connected Google account for resource access"); + } + if (classLogger.isDebugEnabled()) { classLogger.debug("Successfully processed Google OAuth token"); } @@ -2067,24 +2054,13 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe } } - // grab the user again + // Refresh user object from session if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - // Check authentication status based on operation type - boolean isAuthenticated; - if (isConnectOperation) { - // For connect operations, userObj should never be null at this point - // but check defensively - isAuthenticated = (userObj != null && userObj.getResourceAccessToken(AuthProvider.GOOGLE) != null); - } else { - // For login operations - isAuthenticated = (userObj != null && userObj.getAccessToken(AuthProvider.GOOGLE) != null); - } - - if (!isAuthenticated) { - // Not authenticated/connected yet, redirect to start OAuth flow + if (!loginComplete || !connectComplete) { + // Start OAuth flow response.setStatus(302); response.sendRedirect(getGoogleRedirect(request)); return null; From 42cc4c5802c91729c5b6dbe4854646f1dd7121ee Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 <116416780+Subhadeepghosh1@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:59:51 +0530 Subject: [PATCH 11/20] Update UserResource.java --- src/prerna/semoss/web/services/local/UserResource.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index 021d2f9db..fdf9754da 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -186,7 +186,7 @@ public Response logout(@PathParam("provider") String provider, Map ret = new HashMap<>(); ret.put("success", false); ret.put(Constants.ERROR_MESSAGE, "No user is currently logged in the session"); - return WebUtility.getResponse(ret, 401); + return WebUtility.getResponse(ret, 400); } // log the user logout @@ -3437,3 +3437,4 @@ public Response show(@Context HttpServletRequest request, @Context HttpServletRe } } + From 497c07b94c234bfc16466f792443250e56e388b8 Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 <116416780+Subhadeepghosh1@users.noreply.github.com> Date: Fri, 13 Feb 2026 01:48:35 +0530 Subject: [PATCH 12/20] Updated code as per pr review comments --- .../web/services/local/UserResource.java | 281 ++++++++---------- 1 file changed, 124 insertions(+), 157 deletions(-) diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index fdf9754da..d858caacc 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -203,63 +203,34 @@ public Response logout(@PathParam("provider") String provider, removed = true; noUser = true; } else { - AuthProvider token = null; - try { - token = AuthProvider.valueOf(provider.toUpperCase()); - } catch (IllegalArgumentException e) { - classLogger.error("Invalid provider: " + provider, e); - Map ret = new HashMap<>(); - ret.put("success", false); - ret.put(Constants.ERROR_MESSAGE, "Invalid provider: " + provider); - return WebUtility.getResponse(ret, 400); - } - - // Check if this is a login token or a resource access token + AuthProvider token = AuthProvider.valueOf(provider.toUpperCase()); boolean isLoginToken = thisUser.getAccessToken(token) != null; - boolean isResourceToken = thisUser.getResourceAccessToken(token) != null; - - if (!isLoginToken && !isResourceToken) { - // Provider not found in either login or resource tokens - Map ret = new HashMap<>(); - ret.put("success", false); - ret.put(Constants.ERROR_MESSAGE, "Provider " + provider + " is not associated with this user"); - return WebUtility.getResponse(ret, 400); - } + boolean isResourceToken = thisUser.getResourceToken(token) != null; - // Handle resource token removal (takes precedence as it's safer) - if (isResourceToken && !isLoginToken) { - // This is ONLY a resource access token (for data integrations), just remove it - removed = thisUser.dropResourceAccessToken(token); - classLogger.info("User disconnected from resource provider " + provider); - } else if (isLoginToken) { - // This is a login token (may also have resource token) - // Remove both login and resource tokens if both exist + if (isResourceToken) { + thisUser.dropResourceAccessToken(token); + } + if (isLoginToken) { String assetEngineId = null; String workspaceEngineId = null; - - // Capture workspace/asset IDs before dropping if this is the last login + + // TODO: what does this part do? + // TODO: feel like when logout need to adjust the asset id if (thisUser.getLogins().size() == 1) { - assetEngineId = thisUser.getAssetProjectId(token); - workspaceEngineId = thisUser.getWorkspaceProjectId(token); + thisUser.getAssetProjectId(token); + thisUser.getWorkspaceProjectId(token); } removed = thisUser.dropAccessToken(token); - - // Also remove resource token if it exists - if (isResourceToken) { - thisUser.dropResourceAccessToken(token); - classLogger.info("Removed both login and resource tokens for provider " + provider); - } - if (thisUser.getLogins().isEmpty()) { noUser = true; } else { - session.setAttribute(Constants.SESSION_USER, thisUser); - + request.getSession().setAttribute(Constants.SESSION_USER, thisUser); + SyncUserAppsThread sync = new SyncUserAppsThread(workspaceEngineId, assetEngineId); Thread t = new Thread(sync); t.start(); - - // Update the workspace and asset maps + + // put the new map for the user space session.setAttribute(Constants.USER_WORKSPACE_IDS, thisUser.getWorkspaceEngineMap()); session.setAttribute(Constants.USER_ASSET_IDS, thisUser.getAssetEngineMap()); } @@ -1935,7 +1906,6 @@ private String getDBRedirect(HttpServletRequest request) throws UnsupportedEncod return redirectUrl; } - /** * Logs user in through google or connects google for resource access * https://developers.google.com/api-client-library/java/google-api-java-client/oauth2 @@ -1944,130 +1914,126 @@ private String getDBRedirect(HttpServletRequest request) throws UnsupportedEncod @Produces("application/json") @Path("/login/google") public Response loginGoogle(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - boolean loginAllowed = socialData.getLoginsAllowed().get("google") != null - && socialData.getLoginsAllowed().get("google"); - boolean connectAllowed = socialData.getConnectionsAllowed().get("google") != null - && socialData.getConnectionsAllowed().get("google"); - - // At least one operation must be allowed login/connect - if (!loginAllowed && !connectAllowed) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Google login/connection is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - // Determine operation type based on flag values - boolean isLoginOperation = loginAllowed; - boolean isConnectOperation = connectAllowed; - - // For connect operations, user must already be logged in - HttpSession session = request.getSession(false); - User userObj = null; - if (session != null) { - userObj = (User) session.getAttribute(Constants.SESSION_USER); - } - - // A user must be already logged in before we can connect - if (isConnectOperation && (userObj == null || userObj.getLogins().isEmpty())) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "User must be logged in to connect Google account"); - return WebUtility.getResponse(ret, 401); - } - - String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); - if (customRedirect != null && !customRedirect.isEmpty()) { - if (session == null) { - session = request.getSession(); - } - session.setAttribute(CUSTOM_REDIRECT_SESSION_KEY, customRedirect); - } - - boolean loginComplete = (userObj != null && userObj.getAccessToken(AuthProvider.GOOGLE) != null); - boolean connectComplete = (userObj != null && userObj.getResourceAccessToken(AuthProvider.GOOGLE) != null); - - // Process OAuth callback if code is present - String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); - if (queryString != null && queryString.contains("code")) { - if (!loginComplete || !connectComplete) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - String code = URLDecoder.decode(outputs[0]); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - if (code.matches("[ -~]+")) { - String prefix = "google_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + throws IOException { + // Get allowed operation + boolean loginAllowed = socialData.getLoginsAllowed().get("google") != null && socialData.getLoginsAllowed().get("google"); + boolean connectAllowed = socialData.getConnectionsAllowed().get("google") != null && socialData.getConnectionsAllowed().get("google"); + + // Check atleast one of the operation should be allowed + if (!loginAllowed && !connectAllowed) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Google login/connection is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + // Get session and user + HttpSession session = request.getSession(false); + User userObj = null; + if (session != null) { + userObj = (User) session.getAttribute(Constants.SESSION_USER); + } + + // Handle custom redirect + String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); + if (customRedirect != null && !customRedirect.isEmpty()) { + if (session == null) { + session = request.getSession(); + } + session.setAttribute(CUSTOM_REDIRECT_SESSION_KEY, customRedirect); + } + + // Check if login not allowed and connection is allowed + // A user should be logged if connection allowed + if (connectAllowed && !loginAllowed && (userObj == null || userObj.getLogins().isEmpty())) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "User must be logged in to connect Google account"); + return WebUtility.getResponse(ret, 401); + } + + // Check completion status of both the operations + boolean loginComplete = (userObj != null && userObj.getAccessToken(AuthProvider.GOOGLE) != null); + boolean connectComplete = (userObj != null && userObj.getResourceAccessToken(AuthProvider.GOOGLE) != null); + + // Determine what needs to be done + boolean needsLogin = loginAllowed && !loginComplete; + boolean needsConnect = connectAllowed && !connectComplete; + + // Process OAuth callback if code is present + String queryString = WebUtility.encodeHTTPUri(request.getQueryString()); + if (queryString != null && queryString.contains("code")) { + if (needsLogin || needsConnect) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + String code = URLDecoder.decode(outputs[0]); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + if (code.matches("[ -~]+")) { + String prefix = "google_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + if (classLogger.isDebugEnabled()) { + classLogger.debug(">> " + Utility.cleanLogString(request.getQueryString())); + } + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("grant_type", "authorization_code"); + params.put("client_secret", clientSecret); + + String url = "https://www.googleapis.com/oauth2/v4/token"; - if (classLogger.isDebugEnabled()) { - classLogger.debug(">> " + Utility.cleanLogString(request.getQueryString())); + // https://developers.google.com/api-client-library/java/google-api-java-client/oauth2 + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); + if (accessToken == null) { + classLogger.error("Failed to obtain access token from Google"); + response.setStatus(302); + response.sendRedirect(getGoogleRedirect(request)); + return null; } + accessToken.setProvider(AuthProvider.GOOGLE); - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("grant_type", "authorization_code"); - params.put("client_secret", clientSecret); - - String url = "https://www.googleapis.com/oauth2/v4/token"; - - try { - // Get access token from Google (same for both operations) - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); - if (accessToken == null) { - classLogger.error("Failed to obtain access token from Google"); - response.setStatus(302); - response.sendRedirect(getGoogleRedirect(request)); - return null; - } - accessToken.setProvider(AuthProvider.GOOGLE); - - // Fill the access token with user profile information - GoogleTokenFiller profiler = new GoogleTokenFiller(); - profiler.fillAccessToken(accessToken, null, null, null, null); + // Fill the access token with user profile information + GoogleTokenFiller profiler = new GoogleTokenFiller(); + profiler.fillAccessToken(accessToken, null, null, null, null); - // Add token based on which operations are allowed - if (isLoginOperation) { - addAccessToken(accessToken, request, autoAdd); - classLogger.info("User logged in with Google"); - } + // Add to login if allowed and needed + if (loginAllowed) { + addAccessToken(accessToken, request, autoAdd); + classLogger.info("User logged in with Google"); + } - if (isConnectOperation) { - addResourceAccessToken(accessToken, request); - classLogger.info("User connected Google account for resource access"); - } + // Add to resource if allowed and needed + if (connectAllowed) { + addResourceAccessToken(accessToken, request); + classLogger.info("User connected Google account for resource access"); + } - if (classLogger.isDebugEnabled()) { - classLogger.debug("Successfully processed Google OAuth token"); - } - } catch (Exception e) { - classLogger.error("Error during Google OAuth token exchange", e); - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Failed to authenticate with Google: " + e.getMessage()); - return WebUtility.getResponse(ret, 500); + if (classLogger.isDebugEnabled()) { + classLogger.debug("Successfully processed Google OAuth token"); } - } - } - } + } + } + } - // Refresh user object from session + // grab the user again if (session != null || (session = request.getSession(false)) != null) { userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (!loginComplete || !connectComplete) { - // Start OAuth flow - response.setStatus(302); - response.sendRedirect(getGoogleRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; + if (needsLogin || needsConnect) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getGoogleRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; } private String getGoogleRedirect(HttpServletRequest request) throws UnsupportedEncodingException { @@ -3438,3 +3404,4 @@ public Response show(@Context HttpServletRequest request, @Context HttpServletRe } + From 53fdb0d39400ed3b799ea2b8e0a8ded688e79612 Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 <116416780+Subhadeepghosh1@users.noreply.github.com> Date: Tue, 17 Feb 2026 13:56:50 +0530 Subject: [PATCH 13/20] fixed method name --- src/prerna/semoss/web/services/local/UserResource.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index d858caacc..953522bac 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -205,7 +205,7 @@ public Response logout(@PathParam("provider") String provider, } else { AuthProvider token = AuthProvider.valueOf(provider.toUpperCase()); boolean isLoginToken = thisUser.getAccessToken(token) != null; - boolean isResourceToken = thisUser.getResourceToken(token) != null; + boolean isResourceToken = thisUser.getResourceAccessToken(token) != null; if (isResourceToken) { thisUser.dropResourceAccessToken(token); @@ -3405,3 +3405,4 @@ public Response show(@Context HttpServletRequest request, @Context HttpServletRe } + From cc5cd2bee0706ae919778d031a45bbeca755803c Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 Date: Tue, 17 Feb 2026 15:48:45 +0530 Subject: [PATCH 14/20] fix: Added prompt=consent in the google redirect method for refresh token --- src/prerna/semoss/web/services/local/UserResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index 953522bac..87d6a125c 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -2046,7 +2046,7 @@ private String getGoogleRedirect(HttpServletRequest request) throws UnsupportedE String redirectUrl = "https://accounts.google.com/o/oauth2/v2/auth?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" + URLEncoder.encode(redirectUri, UTF8) + "&access_type=" - + accessType + "&scope=" + URLEncoder.encode(scope, UTF8) + "&state=" + state; + + accessType + "prompt=consent" + "&scope=" + URLEncoder.encode(scope, UTF8) + "&state=" + state; if (classLogger.isDebugEnabled()) { classLogger.debug("Sending redirect.. " + Utility.cleanLogString(redirectUrl)); From 02ecaa9a7065f6476d5fbbe4208219cedf12c567 Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 <116416780+Subhadeepghosh1@users.noreply.github.com> Date: Wed, 18 Feb 2026 18:26:49 +0530 Subject: [PATCH 15/20] Properly update needsLogin and needsconnect flags --- src/prerna/semoss/web/services/local/UserResource.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index 87d6a125c..1cd4c6915 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -2002,14 +2002,18 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe profiler.fillAccessToken(accessToken, null, null, null, null); // Add to login if allowed and needed + // needs logins change to false if (loginAllowed) { addAccessToken(accessToken, request, autoAdd); + needsLogin = false; classLogger.info("User logged in with Google"); } // Add to resource if allowed and needed + // needs connect change to false if (connectAllowed) { addResourceAccessToken(accessToken, request); + needsConnect = false; classLogger.info("User connected Google account for resource access"); } @@ -2025,8 +2029,7 @@ public Response loginGoogle(@Context HttpServletRequest request, @Context HttpSe userObj = (User) session.getAttribute(Constants.SESSION_USER); } - if (needsLogin || needsConnect) { - // not authenticated + if (needsLogin || needsConnect) { response.setStatus(302); response.sendRedirect(getGoogleRedirect(request)); return null; @@ -3406,3 +3409,4 @@ public Response show(@Context HttpServletRequest request, @Context HttpServletRe + From 4ebd68de979ab350ff233f2d51b45fae17d44b88 Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 Date: Mon, 11 May 2026 14:59:08 +0530 Subject: [PATCH 16/20] fix: Removed merge conflicts and code cleanup --- .../config/ServerConfigurationResource.java | 4 +- .../web/services/local/UserResource.java | 7787 +++++++++-------- 2 files changed, 3958 insertions(+), 3833 deletions(-) diff --git a/src/prerna/semoss/web/services/config/ServerConfigurationResource.java b/src/prerna/semoss/web/services/config/ServerConfigurationResource.java index e6925552f..427f1b3d4 100644 --- a/src/prerna/semoss/web/services/config/ServerConfigurationResource.java +++ b/src/prerna/semoss/web/services/config/ServerConfigurationResource.java @@ -302,8 +302,8 @@ private static Map getConfiguration(@Context HttpServletRequest clientConfig.put("engineMetaKeys", SecurityEngineUtils.getMetakeyOptions(null)); clientConfig.put("projectMetaKeys", SecurityProjectUtils.getMetakeyOptions(null)); clientConfig.put("insightMetaKeys", SecurityInsightUtils.getMetakeyOptions(null)); - clientConfig.put("userMetaKeys", SecurityUserUtils.getMetakeyOptions(null)); - clientConfig.put("notificationEnabled", Utility.isNotificationDatabaseEnabled()); + clientConfig.put("userMetaKeys", SecurityUserUtils.getMetakeyOptions(null)); + clientConfig.put("notificationEnabled", Utility.isNotificationDatabaseEnabled()); clientConfig.put("auditLogEnabled", Utility.isAuditLogsDatabaseEnabled()); // current date clientConfig.put("systemDate", new SemossDate(Utility.getCurrentZonedDateTimeUTC())); diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index 82ee75c11..1bc283a6d 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -1,3831 +1,3956 @@ -/******************************************************************************* - * Copyright 2015 Defense Health Agency (DHA) - * - * If your use of this software does not include any GPLv2 components: - * 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. - * ---------------------------------------------------------------------------- - * If your use of this software includes any GPLv2 components: - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - *******************************************************************************/ -package prerna.semoss.web.services.local; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.security.Principal; -import java.util.ArrayList; -import java.util.Base64; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.UUID; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import javax.annotation.security.PermitAll; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.NewCookie; -import javax.ws.rs.core.Response; - -import org.apache.http.client.ClientProtocolException; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.javatuples.Pair; -import org.json.JSONArray; -import org.owasp.encoder.Encode; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.base.Strings; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; - -import prerna.auth.AccessToken; -import prerna.auth.AuthProvider; -import prerna.auth.SyncUserAssetsThread; -import prerna.auth.User; -import prerna.auth.external.ExternalAuthorizationHelper; -import prerna.auth.utils.AbstractSecurityUtils; -import prerna.auth.utils.SecurityAPIUserUtils; -import prerna.auth.utils.SecurityAdminUtils; -import prerna.auth.utils.SecurityExternalConnectorsUtils; -import prerna.auth.utils.SecurityNativeUserUtils; -import prerna.auth.utils.SecurityUpdateUtils; -import prerna.auth.utils.SecurityUserUtils; -import prerna.cluster.util.ClusterUtil; -import prerna.io.connector.GenericTokenFiller; -import prerna.io.connector.github.GithubTokenFiller; -import prerna.io.connector.google.GoogleTokenFiller; -import prerna.io.connector.jira.JiraTokenFiller; -import prerna.io.connector.ms.MicrosoftTokenFiller; -import prerna.io.connector.okta.OktaTokenFiller; -import prerna.io.connector.salesforce.SalesforceTokenFiller; -import prerna.io.connector.servicenow.ServiceNowTokenFiller; -import prerna.io.connector.surveymonkey.MonkeyProfile; -import prerna.sablecc2.om.execptions.SemossPixelException; -import prerna.security.HttpHelperUtility; -import prerna.usertracking.UserTrackingUtils; -import prerna.util.BeanFiller; -import prerna.util.Constants; -import prerna.util.SocialPropertiesUtil; -import prerna.util.Utility; -import prerna.util.git.GitRepoUtils; -import prerna.util.ldap.ILdapAuthenticator; -import prerna.util.ldap.LDAPPasswordChangeRequiredException; -import prerna.util.linotp.LinOTPResponse; -import prerna.util.linotp.LinOTPUtil; -import prerna.web.conf.DBLoader; -import prerna.web.conf.UserSessionLoader; -import prerna.web.services.util.WebUtility; -import waffle.servlet.WindowsPrincipal; - -@Path("/auth") -@PermitAll -public class UserResource { - - private static final Logger classLogger = LogManager.getLogger(UserResource.class); - - private static final String CUSTOM_REDIRECT_SESSION_KEY = "custom_redirect"; - - private static SocialPropertiesUtil socialData = null; - static { - socialData = SocialPropertiesUtil.getInstance(); - } - - private static final Charset UTF8 = Charset.forName("UTF-8"); - - /** - * Returns the active login providers for the current session user. - * - * @param request inbound HTTP request - * @return provider-name map response - */ - @GET - @Path("/logins") - public Response getAllLogins(@Context HttpServletRequest request) { - List newCookies = new ArrayList<>(); - HttpSession session = request.getSession(false); - User semossUser = null; - if (session != null) { - semossUser = (User) session.getAttribute(Constants.SESSION_USER); - } - - if (semossUser == null) { - // not authenticated - // remove any cookies we shouldn't have - WebUtility.expireSessionCookies(request, newCookies); - - if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { - session.invalidate(); - } - } - - Map retMap = User.getLoginNames(semossUser); - return WebUtility.getResponse(retMap, 200, newCookies.toArray(new NewCookie[] {})); - } - - /** - * Logs a user out of one provider or all providers in the current session. - * - * @param provider provider name or {@code ALL} - * @param disableRedirect when true, do not send a redirect response - * @param request inbound HTTP request - * @param response outbound HTTP response - * @return logout result payload - * @throws IOException when redirect writing fails - */ - @GET - @Produces("application/json") - @Path("/logout/{provider}") - public Response logout(@PathParam("provider") String provider, - @QueryParam("disableRedirect") boolean disableRedirect, @Context HttpServletRequest request, - @Context HttpServletResponse response) throws IOException { - boolean noUser = false; - boolean removed = false; - - provider = WebUtility.inputSanitizer(provider); - - HttpSession session = request.getSession(); - User thisUser = (User) session.getAttribute(Constants.SESSION_USER); - if (thisUser == null) { - Map ret = new HashMap<>(); - ret.put("success", false); - ret.put(Constants.ERROR_MESSAGE, "No user is currently logged in the session"); - return WebUtility.getResponse(ret, 400); - } - - // log the user logout - classLogger.info("User is logging out of provider {}", provider); - provider = WebUtility.inputSanitizer(provider); - if (provider.equalsIgnoreCase("ALL")) { - removed = true; - noUser = true; - } else { - AuthProvider token = AuthProvider.valueOf(provider.toUpperCase()); - String assetEngineId = null; - - // TODO: what does this part do? - // TODO: feel like when logout need to adjust the asset id - if (thisUser.getLogins().size() == 1) { - thisUser.getAssetProjectId(token); - } - removed = thisUser.dropAccessToken(token); - if (thisUser.getLogins().isEmpty()) { - noUser = true; - } else { - request.getSession().setAttribute(Constants.SESSION_USER, thisUser); - Thread.ofVirtual().start(new SyncUserAssetsThread(assetEngineId)); - // put the new map for the user space - session.setAttribute(Constants.USER_ASSET_IDS, thisUser.getAssetEngineMap()); - } - } - - List nullCookies = null; - if (noUser) { - // when we call session.invalidate() the UserSessionLoader will properly log is - // user logout or tomcat ending - session.setAttribute(UserSessionLoader.IS_USER_LOGOUT, true); - classLogger.info("User has logged out from all providers in the session"); - // well, you have logged out and we always require a login - // so i will redirect you by default unless you specifically say not to - if (!disableRedirect) { - response.setStatus(302); - - String customUrl = DBLoader.getCustomLogoutUrl(); - if (customUrl != null && !customUrl.isEmpty()) { - response.setHeader("redirect", customUrl); - response.sendError(302, "Need to redirect to " + customUrl); - } else { - String redirectUrl = WebUtility.inputSanitizer(request.getHeader("referer")); - if (DBLoader.useLogoutPage()) { - String scheme = WebUtility.inputSanitizer(request.getScheme()); - if (!scheme.trim().equalsIgnoreCase("https") && !scheme.trim().equalsIgnoreCase("http")) { - throw new IllegalArgumentException("scheme is invalid, please input proper scheme"); - } - String serverName = WebUtility.inputSanitizer(request.getServerName()); // hostname.com - int serverPort = request.getServerPort(); // 8080 - String contextPath = WebUtility.inputSanitizer(request.getContextPath()); // /Monolith - - redirectUrl = ""; - redirectUrl += scheme + "://" + serverName; - if (serverPort != 80 && serverPort != 443) { - redirectUrl += ":" + serverPort; - } - redirectUrl += contextPath + "/logout/"; - response.setHeader("redirect", redirectUrl); - response.sendError(302, "Need to redirect to " + redirectUrl); - } else { - redirectUrl = redirectUrl + WebUtility.determineLoginExtension(request); - String encodedRedirectUrl = Encode.forHtml(redirectUrl); - response.setHeader("redirect", encodedRedirectUrl); - response.sendError(302, "Need to redirect to " + encodedRedirectUrl); - } - } - } - - // remove the cookie from the browser - // for the session id - classLogger.info("Removing session token"); - nullCookies = new ArrayList<>(); - WebUtility.expireSessionCookies(request, nullCookies); - // invalidate the session - session.invalidate(); - } - - Map ret = new HashMap<>(); - ret.put("success", removed); - if (nullCookies == null) { - return WebUtility.getResponse(ret, 200); - } - - return WebUtility.getResponseNoCache(ret, 200, nullCookies.toArray(new NewCookie[] {})); - } - - /** - * Adds or updates an authenticated access token in the current user session. - * - * @param token normalized access token - * @param request inbound HTTP request - * @param autoAdd when true, create/update the user record automatically - */ - public static void addAccessToken(AccessToken token, HttpServletRequest request, boolean autoAdd) { - HttpSession session = request.getSession(); - User semossUser = (User) session.getAttribute(Constants.SESSION_USER); - // all of this is now in the user - boolean firstLogin = semossUser == null; - if (firstLogin) { - semossUser = new User(); - session.setAttribute(Constants.SESSION_USER_ID_LOG, token.getId()); - } - // add new users into the database - if (autoAdd) { - SecurityUpdateUtils.addOAuthUser(token); - } - // validate the user's login - // that they are not locked - // and to update the last login date - try { - SecurityUpdateUtils.validateUserLogin(token); - } catch (Exception e) { - classLogger.error("Unexpected error in addAccessToken", e); - } - semossUser.setAccessToken(token); - semossUser.setAnonymous(false); - - // also set the user metadata - SecurityUserUtils.loadUserMetadata(token); - - session.setAttribute(Constants.SESSION_USER, semossUser); - WebUtility.loggingContextLoginEvent(session); - - UserResource.userTrackingLogin(request, semossUser, token.getProvider()); - - // log the user login - classLogger.info("User is logging in with provider {}", token.getProvider()); - - // only for first login - // lets see if there is an external auth - // that we should be loading - if (firstLogin && Boolean - .parseBoolean(Utility.getDIHelperProperty(Constants.EXTERNAL_PERMISSION_MANAGEMENT_ENABLED) + "")) { - try { - ExternalAuthorizationHelper.updateEnginePermissionsBasedOnApiCall(semossUser); - } catch (Exception e) { - classLogger.error("Unexpected error in addAccessToken", e); - } - } - } - - /** - * Records a user login event in the tracking system. - * - * @param request inbound HTTP request - * @param semossUser authenticated user - * @param ap authentication provider used for login - */ - public static void userTrackingLogin(HttpServletRequest request, User semossUser, AuthProvider ap) { - String ip = WebUtility.getClientIp(request); - if (request.getSession() != null && request.getSession().getId() != null) { - UserTrackingUtils.registerLogin(request.getSession().getId(), ip, semossUser, ap); - } else { - UserTrackingUtils.registerLogin("NO_SESSION_ID", ip, semossUser, ap); - } - } - - ////////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////// - - /** - * User info method calls - */ - - /** - * Gets user profile information for ADFS. - */ - @GET - @Produces("application/json") - @Path("/userinfo/adfs") - public Response userinfoADFS(@Context HttpServletRequest request) { - Map ret = new HashMap<>(); - HttpSession session = request.getSession(false); - User semossUser = null; - if (session != null) { - semossUser = (User) session.getAttribute(Constants.SESSION_USER); - } - - if (semossUser == null) { - List newCookies = new ArrayList<>(); - // not authenticated - // remove any cookies we shouldn't have - WebUtility.expireSessionCookies(request, newCookies); - - if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { - session.invalidate(); - } - - ret.put(Constants.ERROR_MESSAGE, "Log into your ADFS account"); - return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); - } - - String prefix = "adfs_"; - String beanProps = socialData.getProperty(prefix + "beanProps"); - String jsonPattern = socialData.getProperty(prefix + "jsonPattern"); - - String[] beanPropsArr = beanProps.split(",", -1); - - String accessString = null; - try { - AccessToken adfsToken = semossUser.getAccessToken(AuthProvider.ADFS); - accessString = adfsToken.getAccess_token(); - String json = decodeTokenPayload(adfsToken.getAccess_token()); - adfsToken = (AccessToken) BeanFiller.fillFromJson(json, jsonPattern, beanPropsArr, adfsToken); - String name = adfsToken.getName(); - ret.put("name", name); - - return WebUtility.getResponse(ret, 200); - } catch (Exception e) { - ret.put(Constants.ERROR_MESSAGE, "Log into your ADFS account"); - return WebUtility.getResponse(ret, 200); - } - } - - /** - * Gets user profile information for Dropbox. - */ - @GET - @Produces("application/json") - @Path("/userinfo/dropbox") - public Response userinfoDropbox(@Context HttpServletRequest request) { - Map ret = new HashMap<>(); - HttpSession session = request.getSession(false); - User semossUser = null; - if (session != null) { - semossUser = (User) session.getAttribute(Constants.SESSION_USER); - } - - if (semossUser == null) { - List newCookies = new ArrayList<>(); - // not authenticated - // remove any cookies we shouldn't have - WebUtility.expireSessionCookies(request, newCookies); - - if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { - session.invalidate(); - } - - ret.put(Constants.ERROR_MESSAGE, "Log into your DropBox account"); - return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); - } - - String[] beanProps = { "name", "profile" }; // add is done when you have a list - String jsonPattern = "[name.display_name, profile_photo_url]"; - String accessString = null; - try { - AccessToken dropToken = semossUser.getAccessToken(AuthProvider.DROPBOX); - accessString = dropToken.getAccess_token(); - } catch (Exception e) { - ret.put(Constants.ERROR_MESSAGE, "Log into your DropBox account"); - return WebUtility.getResponse(ret, 200); - } - String url = "https://api.dropboxapi.com/2/users/get_current_account"; - - String output = HttpHelperUtility.makePostCall(url, accessString, null, true); - AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, - new AccessToken()); - try { - if (accessToken2.getProfile() == null || accessToken2.getProfile().equalsIgnoreCase("null")) { - ret.put("picture", ""); - } else { - ret.put("picture", accessToken2.getProfile()); - } - ret.put("name", accessToken2.getName()); - } catch (Exception e) { - classLogger.error("Unexpected error in userinfoDropbox", e); - } - return WebUtility.getResponse(ret, 200); - - } - - /** - * Gets user profile information for GitHub. - */ - @GET - @Produces("application/json") - @Path("/userinfo/github") - public Response userinfoGithub(@Context HttpServletRequest request) { - Map ret = new HashMap<>(); - HttpSession session = request.getSession(false); - User semossUser = null; - if (session != null) { - semossUser = (User) session.getAttribute(Constants.SESSION_USER); - } - - if (semossUser == null) { - List newCookies = new ArrayList<>(); - // not authenticated - // remove any cookies we shouldn't have - WebUtility.expireSessionCookies(request, newCookies); - - if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { - session.invalidate(); - } - - ret.put(Constants.ERROR_MESSAGE, "Log into your Github account"); - return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); - } - - String[] beanProps = { "name", "profile" }; // add is done when you have a list - String jsonPattern = "[name,login]"; - - String accessString = null; - try { - AccessToken gitToken = semossUser.getAccessToken(AuthProvider.GITHUB); - accessString = gitToken.getAccess_token(); - } catch (Exception e) { - ret.put(Constants.ERROR_MESSAGE, "Log into your Github account"); - return WebUtility.getResponse(ret, 200); - } - - String url = "https://api.github.com/user"; - - String output = HttpHelperUtility.makeGetCall(url, accessString, null, true); - AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, - new AccessToken()); - try { - ret.put("name", accessToken2.getProfile()); - } catch (Exception e) { - classLogger.error("Unexpected error in userinfoGithub", e); - } - return WebUtility.getResponse(ret, 200); - } - - /** - * Gets user profile information for Google. - */ - @GET - @Produces("application/json") - @Path("/userinfo/google") - public Response userinfoGoogle(@Context HttpServletRequest request) { - Map ret = new HashMap<>(); - HttpSession session = request.getSession(false); - User semossUser = null; - if (session != null) { - semossUser = (User) session.getAttribute(Constants.SESSION_USER); - } - - if (semossUser == null) { - List newCookies = new ArrayList<>(); - // not authenticated - // remove any cookies we shouldn't have - WebUtility.expireSessionCookies(request, newCookies); - - if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { - session.invalidate(); - } - - ret.put(Constants.ERROR_MESSAGE, "Log into your Google account"); - return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); - } - - String[] beanProps = { "name", "profile" }; - String jsonPattern = "[name, picture]"; - String accessString = null; - try { - AccessToken googleToken = semossUser.getAccessToken(AuthProvider.GOOGLE); - accessString = googleToken.getAccess_token(); - } catch (Exception e) { - ret.put(Constants.ERROR_MESSAGE, "Log into your Google account"); - return WebUtility.getResponse(ret, 200); - } - - String url = "https://www.googleapis.com/oauth2/v3/userinfo"; - Map params = new HashMap<>(); - params.put("access_token", accessString); - params.put("alt", "json"); - - String output = HttpHelperUtility.makeGetCall(url, accessString, params, true); - AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, - new AccessToken()); - try { - ret.put("name", accessToken2.getName()); - if (accessToken2.getProfile() != null) { - ret.put("picture", accessToken2.getProfile()); - } - } catch (Exception e) { - classLogger.error("Unexpected error in userinfoGoogle", e); - } - - return WebUtility.getResponse(ret, 200); - } - - /** - * Gets user profile information for Jira. - */ - @GET - @Produces("application/json") - @Path("/userinfo/jira") - public Response userinfoJira(@Context HttpServletRequest request) { - Map ret = new HashMap<>(); - HttpSession session = request.getSession(false); - User semossUser = null; - if (session != null) { - semossUser = (User) session.getAttribute(Constants.SESSION_USER); - } - if (semossUser == null) { - List newCookies = new ArrayList<>(); - // not authenticated - // remove any cookies we shouldn't have - WebUtility.expireSessionCookies(request, newCookies); - if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { - session.invalidate(); - } - ret.put(Constants.ERROR_MESSAGE, "Log into your Jira account"); - return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); - } - String[] beanProps = { "name" }; - String jsonPattern = "[name]"; - String accessString = null; - try { - AccessToken jiraToken = semossUser.getAccessToken(AuthProvider.JIRA); - accessString = jiraToken.getAccess_token(); - String url = "https://api.atlassian.com/me"; - Map params = new HashMap<>(); - params.put("access_token", accessString); - params.put("alt", "json"); - String output = HttpHelperUtility.makeGetCall(url, accessString, params, true); - AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, - new AccessToken()); - String name = accessToken2.getName(); - ret.put("name", name); - return WebUtility.getResponse(ret, 200); - } catch (Exception e) { - classLogger.error("Failed to fetch Jira user info", e); - ret.put(Constants.ERROR_MESSAGE, "Log into your Jira account"); - return WebUtility.getResponse(ret, 401); - } - } - - /** - * Backwards-compatible alias for the Microsoft user-info endpoint. - */ - @GET - @Produces("application/json") - @Path("/userinfo/ms") - @Deprecated - public Response userinfoMs(@Context HttpServletRequest request) { - return userinfoMicrosoft(request); - } - - /** - * Gets user profile information for Microsoft. - * - * @param request inbound HTTP request - * @return user info response for Microsoft - */ - @GET - @Produces("application/json") - @Path("/userinfo/microsoft") - public Response userinfoMicrosoft(@Context HttpServletRequest request) { - Map ret = new HashMap<>(); - HttpSession session = request.getSession(false); - User semossUser = null; - if (session != null) { - semossUser = (User) session.getAttribute(Constants.SESSION_USER); - } - - if (semossUser == null) { - List newCookies = new ArrayList<>(); - // not authenticated - // remove any cookies we shouldn't have - WebUtility.expireSessionCookies(request, newCookies); - - if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { - session.invalidate(); - } - - ret.put(Constants.ERROR_MESSAGE, "Log into your Microsoft account"); - return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); - } - - String[] beanProps = { "name" }; - String jsonPattern = "[displayName]"; - - String accessString = null; - try { - AccessToken msToken = semossUser.getAccessToken(AuthProvider.MICROSOFT); - accessString = msToken.getAccess_token(); - String url = "https://graph.microsoft.com/v1.0/me/"; - String output = HttpHelperUtility.makeGetCall(url, accessString, null, true); - AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, - new AccessToken()); - String name = accessToken2.getName(); - ret.put("name", name); - return WebUtility.getResponse(ret, 200); - - } catch (Exception e) { - ret.put(Constants.ERROR_MESSAGE, "Log into your Microsoft account"); - return WebUtility.getResponse(ret, 200); - } - } - - /** - * Gets user profile information for Okta. - * - * @param request inbound HTTP request - * @return user info response for Okta - */ - @GET - @Produces("application/json") - @Path("/userinfo/okta") - public Response userinfoOkta(@Context HttpServletRequest request) { - String prefix = "okta_"; - - Map ret = new HashMap<>(); - HttpSession session = request.getSession(false); - User semossUser = null; - if (session != null) { - semossUser = (User) session.getAttribute(Constants.SESSION_USER); - } - - if (semossUser == null) { - List newCookies = new ArrayList<>(); - // not authenticated - // remove any cookies we shouldn't have - WebUtility.expireSessionCookies(request, newCookies); - - if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { - session.invalidate(); - } - - ret.put(Constants.ERROR_MESSAGE, "Log into your Okta account"); - return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); - } - - String[] beanPropsArr = { "id", "name", "email", "phone" }; - String jsonPattern = "[sub,name,email,phone_number]"; - - String accessString = null; - try { - AccessToken accessToken = semossUser.getAccessToken(AuthProvider.OKTA); - accessString = accessToken.getAccess_token(); - String userInfoURL = socialData.getProperty(prefix + "userinfo_url"); - String socialBeanProps = socialData.getProperty(prefix + "beanProps"); - - if (socialBeanProps != null && !socialBeanProps.trim().isEmpty()) { - beanPropsArr = socialBeanProps.split(",", -1); - } - - String socialJsonPattern = socialData.getProperty(prefix + "jsonPattern"); - - if (socialJsonPattern != null && !socialJsonPattern.trim().isEmpty()) { - jsonPattern = socialJsonPattern; - } - - String output = HttpHelperUtility.makeGetCall(userInfoURL, accessString, null, true); - AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanPropsArr, - new AccessToken()); - String name = accessToken2.getName(); - ret.put("name", name); - return WebUtility.getResponse(ret, 200); - } catch (Exception e) { - ret.put(Constants.ERROR_MESSAGE, "Log into your Okta account"); - return WebUtility.getResponse(ret, 200); - } - } - - /** - * Gets user profile information for Salesforce. - */ - @GET - @Produces("application/json") - @Path("/userinfo/salesforce") - public Response userinfoSalesforce(@Context HttpServletRequest request) { - Map ret = new HashMap<>(); - HttpSession session = request.getSession(false); - User semossUser = null; - if (session != null) { - semossUser = (User) session.getAttribute(Constants.SESSION_USER); - } - - if (semossUser == null) { - List newCookies = new ArrayList<>(); - // not authenticated - // remove any cookies we shouldn't have - WebUtility.expireSessionCookies(request, newCookies); - - if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { - session.invalidate(); - } - - ret.put(Constants.ERROR_MESSAGE, "Log into your Salesforce account"); - return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); - } - - String[] beanProps = { "name" }; - String jsonPattern = "[name]"; - - String accessString = null; - try { - AccessToken salesforceToken = semossUser.getAccessToken(AuthProvider.SALESFORCE); - accessString = salesforceToken.getAccess_token(); - String url = "https://login.salesforce.com/services/oauth2/userinfo"; - Map params = new HashMap<>(); - params.put("access_token", accessString); - params.put("alt", "json"); - - String output = HttpHelperUtility.makeGetCall(url, accessString, params, true); - AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, - new AccessToken()); - String name = accessToken2.getName(); - ret.put("name", name); - return WebUtility.getResponse(ret, 200); - - } catch (Exception e) { - classLogger.error("Failed to fetch Salesforce user info", e); - ret.put(Constants.ERROR_MESSAGE, "Log into your Salesforce account"); - return WebUtility.getResponse(ret, 401); - } - - } - - /** - * Gets user profile information for ServiceNow. - */ - @GET - @Produces("application/json") - @Path("/userinfo/servicenow") - public Response userinfoServiceNow(@Context HttpServletRequest request) { - Map ret = new HashMap<>(); - HttpSession session = request.getSession(false); - User semossUser = null; - if (session != null) { - semossUser = (User) session.getAttribute(Constants.SESSION_USER); - } - - if (semossUser == null) { - List newCookies = new ArrayList<>(); - // not authenticated - // remove any cookies we shouldn't have - WebUtility.expireSessionCookies(request, newCookies); - - if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { - session.invalidate(); - } - - ret.put(Constants.ERROR_MESSAGE, "Log into your ServiceNow account"); - return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); - } - - String[] beanProps = { "name" }; - String jsonPattern = "[result.name]"; - - String accessString = null; - try { - AccessToken servicenowToken = semossUser.getAccessToken(AuthProvider.SERVICENOW); - accessString = servicenowToken.getAccess_token(); - String prefix = "servicenow_"; - String userinfoUrl = socialData.getProperty(prefix + "userinfo_url"); - Map params = new HashMap<>(); - params.put("access_token", accessString); - params.put("alt", "json"); - - String output = HttpHelperUtility.makeGetCall(userinfoUrl, accessString, params, true); - AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, - new AccessToken()); - String name = accessToken2.getName(); - ret.put("name", name); - return WebUtility.getResponse(ret, 200); - - } catch (Exception e) { - classLogger.error("Failed to fetch ServiceNow user info", e); - ret.put(Constants.ERROR_MESSAGE, "Log into your ServiceNow account"); - return WebUtility.getResponse(ret, 401); - } - - } - - /** - * Gets user profile information for a generic OAuth provider. - */ - @GET - @Produces("application/json") - @Path("/userinfo/{provider}") - public Response userinfoGeneric(@PathParam("provider") String provider, @Context HttpServletRequest request) { - provider = WebUtility.inputSanitizer(provider); - - AuthProvider providerEnum = AuthProvider.getProviderFromString(provider.toUpperCase()); - Map ret = new HashMap<>(); - HttpSession session = request.getSession(false); - - User semossUser = null; - if (session != null) { - semossUser = (User) session.getAttribute(Constants.SESSION_USER); - } - - if (semossUser == null) { - List newCookies = new ArrayList<>(); - // not authenticated - // remove any cookies we shouldn't have - WebUtility.expireSessionCookies(request, newCookies); - - if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { - session.invalidate(); - } - - ret.put(Constants.ERROR_MESSAGE, "Log into your " + providerEnum.name() + " account"); - return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); - } - - String prefix = provider + "_"; - String userInfoURL = socialData.getProperty(prefix + "userinfo_url"); - // "name","id","email" - String beanProps = socialData.getProperty(prefix + "beanProps"); - String jsonPattern = socialData.getProperty(prefix + "jsonPattern"); - - String[] beanPropsArr = beanProps.split(",", -1); - - String accessString = null; - try { - AccessToken genericToken = semossUser.getAccessToken(providerEnum); - accessString = genericToken.getAccess_token(); - // String url = "https://graph.microsoft.com/v1.0/me/"; - String output = HttpHelperUtility.makeGetCall(userInfoURL, accessString, null, true); - AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanPropsArr, - new AccessToken()); - String name = accessToken2.getName(); - ret.put("name", name); - - return WebUtility.getResponse(ret, 200); - } catch (Exception e) { - ret.put(Constants.ERROR_MESSAGE, "Log into your " + providerEnum.toString() + " account"); - return WebUtility.getResponse(ret, 200); - } - } - - ////////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////// - - /** - * Initializes an OAuth login flow session and stores a custom redirect value - * when present. - * - * @param request inbound HTTP request - * @return existing or newly-created session - */ - private HttpSession initializeOAuthLoginSession(HttpServletRequest request) { - HttpSession session = request.getSession(false); - String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); - if (customRedirect != null && !customRedirect.isEmpty()) { - if (session == null) { - session = request.getSession(); - } - session.setAttribute(CUSTOM_REDIRECT_SESSION_KEY, customRedirect); - } - return session; - } - - /** - * Resolves the authenticated user from a session. - * - * @param session HTTP session - * @return session user or {@code null} - */ - private User getSessionUser(HttpSession session) { - if (session == null) { - return null; - } - return (User) session.getAttribute(Constants.SESSION_USER); - } - - /** - * Reloads the session user after an OAuth callback updates session state. - * - * @param request inbound HTTP request - * @param session current session reference - * @return session user or {@code null} - */ - private User refreshSessionUser(HttpServletRequest request, HttpSession session) { - if (session != null || (session = request.getSession(false)) != null) { - return (User) session.getAttribute(Constants.SESSION_USER); - } - return null; - } - - /** - * Checks whether a user has an access token for the requested provider. - * - * @param user user to inspect - * @param provider authentication provider - * @return {@code true} when a token exists - */ - private boolean hasAccessToken(User user, AuthProvider provider) { - return user != null && user.getAccessToken(provider) != null; - } - - /** - * Encodes the request query string for safe OAuth parsing. - * - * @param request inbound HTTP request - * @return encoded query string - */ - private String getEncodedQueryString(HttpServletRequest request) { - return WebUtility.encodeHTTPUri(request.getQueryString()); - } - - /** - * Checks whether the callback query contains an OAuth authorization code. - * - * @param queryString encoded callback query string - * @return {@code true} when a code parameter is present - */ - private boolean hasOAuthCode(String queryString) { - return queryString != null && queryString.contains("code"); - } - - /** - * Handles ADFS OAuth login callback flow. - */ - @GET - @Produces("application/json") - @Path("/login/adfs") - public Response loginADFS(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("adfs") == null || !socialData.getLoginsAllowed().get("adfs")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "ADFS login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.ADFS)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String prefix = "adfs_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String scope = socialData.getProperty(prefix + "scope"); - String token_url = socialData.getProperty(prefix + "token_url"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("scope", scope); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("grant_type", "authorization_code"); - params.put("client_secret", clientSecret); - - if (Strings.isNullOrEmpty(token_url)) { - throw new IllegalArgumentException("Token URL can not be null or empty"); - } - - AccessToken accessToken = HttpHelperUtility.getIdToken(token_url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getADFSRedirect(request)); - return null; - } - String json = decodeTokenPayload(accessToken.getAccess_token()); - - accessToken.setProvider(AuthProvider.ADFS); - String beanProps = socialData.getProperty(prefix + "beanProps"); - String jsonPattern = socialData.getProperty(prefix + "jsonPattern"); - String[] beanPropsArr = beanProps.split(",", -1); - accessToken = (AccessToken) BeanFiller.fillFromJson(json, jsonPattern, beanPropsArr, accessToken); - - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.ADFS)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getADFSRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Decodes the JWT payload segment from a token value. - * - * @param token JWT access token - * @return decoded JSON payload - */ - private String decodeTokenPayload(String token) { - String[] parts = token.split("\\.", 0); - byte[] bytes = Base64.getUrlDecoder().decode(parts[1]); - String payload = new String(bytes, StandardCharsets.UTF_8); - return payload; - } - - /** - * Builds the ADFS authorization redirect URL. - * - * @param request inbound HTTP request - * @return ADFS authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getADFSRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "adfs_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String scope = socialData.getProperty(prefix + "scope"); // need to set this up and reuse - String auth_url = socialData.getProperty(prefix + "auth_url"); - - String state = UUID.randomUUID().toString(); - - if (Strings.isNullOrEmpty(auth_url)) { - throw new IllegalArgumentException("A URL can not be null or empty"); - } - String redirectUrl = auth_url + "?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" - + URLEncoder.encode(redirectUri, UTF8) + "&response_mode=query" + "&scope=" - + URLEncoder.encode(scope, UTF8) + "&state=" + state; - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles Dropbox OAuth login callback flow. - */ - @GET - @Produces("application/json") - @Path("/login/dropbox") - public Response loginDropBox(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("dropbox") == null || !socialData.getLoginsAllowed().get("dropbox")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Dropbox login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.DROPBOX)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String prefix = "dropbox_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("grant_type", "authorization_code"); - params.put("client_secret", clientSecret); - - String url = "https://www.dropbox.com/oauth2/token"; - - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getDBRedirect(request)); - return null; - } - accessToken.setProvider(AuthProvider.DROPBOX); - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.DROPBOX)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getDBRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the Dropbox authorization redirect URL. - * - * @param request inbound HTTP request - * @return Dropbox authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getDBRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "dropbox_"; - - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String role = socialData.getProperty(prefix + "role"); // need to set this up and reuse - String redirectUrl = "https://www.dropbox.com/oauth2/authorize?" + "client_id=" + clientId - + "&response_type=code" + "&redirect_uri=" + URLEncoder.encode(redirectUri, UTF8) + "&require_role=" - + role + "&disable_signup=false"; - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles GitHub OAuth login callback flow. - * https://developer.github.com/apps/building-oauth-apps/authorization-options-for-oauth-apps/ - */ - @GET - @Produces("application/json") - @Path("/login/github") - public Response loginGithub(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("github") == null || !socialData.getLoginsAllowed().get("github")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "GitHub login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.GITHUB)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code and state should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.5 - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - String state = URLDecoder.decode(outputs[1], StandardCharsets.UTF_8); - if (code.matches("[ -~]+") && state.matches("[ -~]+")) { - String prefix = "github_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("state", state); - params.put("client_secret", clientSecret); - - String url = "https://github.com/login/oauth/access_token"; - - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, false, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getGithubRedirect(request)); - return null; - } - accessToken.setProvider(AuthProvider.GITHUB); - - try { - GitRepoUtils.addCertForDomain(url); - } catch (Exception e) { - classLogger.error("Unexpected error in loginGithub", e); - } - // add specific Git values - GithubTokenFiller profiler = new GithubTokenFiller(); - profiler.fillAccessToken(accessToken, null, null, null, null); - - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.GITHUB)) { - // not authenticated - try { - GitRepoUtils.addCertForDomain("https://github.com"); - } catch (Exception e) { - classLogger.error("Unexpected error in loginGithub", e); - } - response.setStatus(302); - response.sendRedirect(getGithubRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the GitHub authorization redirect URL. - * - * @param request inbound HTTP request - * @return GitHub authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getGithubRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "github_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String scope = socialData.getProperty(prefix + "scope"); - - String redirectUrl = "https://github.com/login/oauth/authorize?" + "client_id=" + clientId + "&redirect_uri=" - + redirectUri + "&state=" + UUID.randomUUID().toString() + "&allow_signup=true" + "&scope=" - + URLEncoder.encode(scope, UTF8); - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles GitLab OAuth login callback flow. - * https://docs.gitlab.com/13.12/ee/integration/oauth_provider.html - * https://docs.gitlab.com/13.12/ee/api/oauth2.html - */ - @GET - @Produces("application/json") - @Path("/login/gitlab") - public Response loginGitlab(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("gitlab") == null || !socialData.getLoginsAllowed().get("gitlab")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "GitLab login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - String prefix = "gitlab_"; - - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.GITLAB)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code and state should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.5 - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - String state = URLDecoder.decode(outputs[1], StandardCharsets.UTF_8); - if (code.matches("[ -~]+") && state.matches("[ -~]+")) { - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String token_url = socialData.getProperty(prefix + "token_url"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("state", state); - params.put("client_secret", clientSecret); - params.put("grant_type", "authorization_code"); - - AccessToken accessToken = HttpHelperUtility.getAccessToken(token_url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getGitlabRedirect(request)); - return null; - } - accessToken.setProvider(AuthProvider.GITLAB); - - String beanProps = socialData.getProperty(prefix + "beanProps"); - String jsonPattern = socialData.getProperty(prefix + "jsonPattern"); - String userinfo_url = socialData.getProperty(prefix + "userinfo_url"); - String[] beanPropsArr = beanProps.split(",", -1); - - String output = HttpHelperUtility.makeGetCall(userinfo_url, accessToken.getAccess_token(), null, - true); - accessToken = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanPropsArr, accessToken); - - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.GITLAB)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getGitlabRedirect(request)); - return null; - } - - if (Boolean.parseBoolean(socialData.getProperty(prefix + "groups"))) { - // get groups - String group_url = socialData.getProperty(prefix + "group_url"); - String groupsJson = HttpHelperUtility.makeGetCall(group_url, - userObj.getAccessToken(AuthProvider.GITLAB).getAccess_token()); - String groupJsonPattern = socialData.getProperty(prefix + "groupJsonPattern"); - // String beanProps = socialData.getProperty(prefix + "groupBeanProps"); - // String[] beanPropsArr = beanProps.split(",", -1); - Set userGroups = new HashSet(); - - JsonNode result = BeanFiller.getJmesResult(groupsJson, groupJsonPattern); - if ((result instanceof ArrayNode) && result.get(0) instanceof ObjectNode) { - throw new SemossPixelException("Group result must return flat array. Please check groupJsonPatter"); - } - for (int inputIndex = 0; result != null && inputIndex < result.size(); inputIndex++) { - String thisInput = result.get(inputIndex).asText(); - userGroups.add(thisInput); - } - - userObj.getAccessToken(AuthProvider.GITLAB).setUserGroups(userGroups); - userObj.getAccessToken(AuthProvider.GITLAB).setUserGroupType(AuthProvider.GITLAB.toString()); - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the GitLab authorization redirect URL. - * - * @param request inbound HTTP request - * @return GitLab authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getGitlabRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "gitlab_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String scope = socialData.getProperty(prefix + "scope"); - String auth_url = socialData.getProperty(prefix + "auth_url"); - - scope = scope.replaceAll(" ", "+"); - String state = UUID.randomUUID().toString(); - - String redirectUrl = auth_url + "?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" - + URLEncoder.encode(redirectUri, UTF8) + "&scope=" + scope + "&state=" + state; - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles Google OAuth login callback flow. - * https://developers.google.com/api-client-library/java/google-api-java-client/oauth2 - */ - @GET - @Produces("application/json") - @Path("/login/google") - public Response loginGoogle(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("google") == null || !socialData.getLoginsAllowed().get("google")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Google login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.GOOGLE)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String prefix = "google_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - // I need to decode the return code from google since the default param's are - // encoded on the post of getAccessToken - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("grant_type", "authorization_code"); - params.put("client_secret", clientSecret); - - String url = "https://www.googleapis.com/oauth2/v4/token"; - - // https://developers.google.com/api-client-library/java/google-api-java-client/oauth2 - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getGoogleRedirect(request)); - return null; - } - accessToken.setProvider(AuthProvider.GOOGLE); - - // fill the access token with the other properties so we can properly create the - // user - GoogleTokenFiller profiler = new GoogleTokenFiller(); - profiler.fillAccessToken(accessToken, null, null, null, null); - addAccessToken(accessToken, request, autoAdd); - - // Shows how to make a google credential from an access token - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.GOOGLE)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getGoogleRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the Google authorization redirect URL. - * - * @param request inbound HTTP request - * @return Google authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getGoogleRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "google_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String scope = socialData.getProperty(prefix + "scope"); // need to set this up and reuse - String accessType = socialData.getProperty(prefix + "access_type"); // need to set this up and reuse - String state = UUID.randomUUID().toString(); - - String redirectUrl = "https://accounts.google.com/o/oauth2/v2/auth?" + "client_id=" + clientId - + "&response_type=code" + "&redirect_uri=" + URLEncoder.encode(redirectUri, UTF8) + "&access_type=" - + accessType + "&scope=" + URLEncoder.encode(scope, UTF8) + "&state=" + state; - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles Jira OAuth login callback and exchanges the authorization code for a - * token. - * - * @param request inbound HTTP request - * @param response outbound HTTP response - * @return redirect response - * @throws IOException when redirect writing fails - */ - @GET - @Produces("application/json") - @Path("/login2/jira") - public Response loginJiraDynamic(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.JIRA)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String state = URLDecoder.decode(outputs[1], StandardCharsets.UTF_8); - String connectionId = session == null ? null : (String) session.getAttribute("sf_state_" + state); - if (connectionId == null) { - // invalid or tampered state - response.setStatus(400); - return null; - } - session.removeAttribute("sf_state_" + state); - - String redirectUri = WebUtility.getCurrentCallbackUrl(request); - boolean autoAdd = true; - Map details = SecurityExternalConnectorsUtils - .getJiraConnectionDetails(connectionId); - String clientId = (String) details.get("clientId"); - String clientSecret = (String) details.get("clientSecret"); - String userInfoUrl = (String) details.get("userInfoUrl"); - - if (clientId == null || clientSecret == null || redirectUri == null) { - response.setStatus(400); - response.getWriter().write("Jira credentials not found for connection id = " + connectionId); - return null; - } - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("client_secret", clientSecret); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("grant_type", "authorization_code"); - - String url = "https://auth.atlassian.com/oauth/token"; - - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getJiraRedirectDynamic(request, response, connectionId)); - return null; - } - accessToken.setProvider(AuthProvider.JIRA); - // fill the access token with the other properties so we can properly create the - // user - JiraTokenFiller profiler = new JiraTokenFiller(); - profiler.fillAccessToken(accessToken, userInfoUrl, null, null, null); - - String cloudId = fetchJiraCloudId(accessToken.getAccess_token()); - if (cloudId != null) { - accessToken.setId(cloudId); - } - - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Successfully processed Jira OAuth callback. Access Token is.. {}", - accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.JIRA)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getJiraRedirectDynamic(request, response, null)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the Jira dynamic-credential authorization redirect URL. - * - * @param request inbound HTTP request - * @param response outbound HTTP response - * @param connectionId external-connector id - * @return Jira authorize URL or {@code null} when validation fails - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - * @throws IOException when response writing fails - */ - private String getJiraRedirectDynamic(HttpServletRequest request, HttpServletResponse response, String connectionId) - throws UnsupportedEncodingException, IOException { - String redirectUri = WebUtility.getCurrentCallbackUrl(request); - if (connectionId == null) { - connectionId = request.getParameter("connectionId"); - } - if (connectionId == null || connectionId.isEmpty()) { - response.setStatus(400); - response.getWriter().write("Missing required parameter: connectionId"); - return null; - } - - String state = UUID.randomUUID().toString(); - request.getSession().setAttribute("sf_state_" + state, connectionId); - - Map details = SecurityExternalConnectorsUtils.getJiraConnectionDetails(connectionId); - String clientId = (String) details.get("clientId"); - String scope = (String) details.get("scope"); - - if (clientId == null || scope == null || redirectUri == null) { - response.setStatus(400); - response.getWriter().write("Jira credentials not found for connection id = " + connectionId); - return null; - } - - String redirectUrl = "https://auth.atlassian.com/authorize" + "?audience=api.atlassian.com" + "&client_id=" - + URLEncoder.encode(clientId, "UTF-8") + "&scope=" + URLEncoder.encode(scope, "UTF-8") - + "&redirect_uri=" + URLEncoder.encode(redirectUri, "UTF-8") + "&state=" - + URLEncoder.encode(state, "UTF-8") + "&response_type=code" + "&prompt=consent"; - - classLogger.debug("Sending Jira redirect.. {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Fetches the first accessible Jira cloud resource id for a bearer token. - * - * @param bearerToken Jira bearer token - * @return cloud id when available; otherwise {@code null} - */ - private String fetchJiraCloudId(String bearerToken) { - try { - String url = "https://api.atlassian.com/oauth/token/accessible-resources"; - Map params = new HashMap<>(); - String output = HttpHelperUtility.makeGetCall(url, bearerToken, params, true); - JSONArray resources = new JSONArray(output); - if (resources.length() > 0) { - return resources.getJSONObject(0).getString("id"); - } - } catch (Exception e) { - classLogger.error("Failed to fetch Jira accessible resources (cloudId)", e); - } - return null; - } - - /** - * Handles LinkedIn OAuth login callback flow. - */ - @GET - @Produces("application/json") - @Path("/login/linkedin") - public Response loginLinkedin(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("linkedin") == null || !socialData.getLoginsAllowed().get("linkedin")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "LinkedIn login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.LINKEDIN)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String prefix = "linkedin_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("grant_type", "authorization_code"); - params.put("client_secret", clientSecret); - - String url = "https://www.linkedin.com/oauth/v2/accessToken"; - - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getLinkedinRedirect(request)); - return null; - } - accessToken.setProvider(AuthProvider.LINKEDIN); - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.LINKEDIN)) { - response.setStatus(302); - response.sendRedirect(getLinkedinRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the LinkedIn authorization redirect URL. - * - * @param request inbound HTTP request - * @return LinkedIn authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getLinkedinRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "linkedin_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String scope = socialData.getProperty(prefix + "scope"); - - String redirectUrl = "https://www.linkedin.com/oauth/v2/authorization?" + "client_id=" + clientId - + "&redirect_uri=" + redirectUri + "&state=" + UUID.randomUUID().toString() + "&response_type=code" - + "&scope=" + URLEncoder.encode(scope, UTF8); - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Deprecated alias for the Microsoft OAuth login endpoint. - */ - @GET - @Produces("application/json") - @Path("/login/ms") - @Deprecated - public Response loginMS(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - return loginMicrosoft(request, response); - } - - /** - * Handles Microsoft OAuth login callback flow. - * - * @param request inbound HTTP request - * @param response outbound HTTP response - * @return redirect response - * @throws IOException when redirect writing fails - */ - @GET - @Produces("application/json") - @Path("/login/microsoft") - public Response loginMicrosoft(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("ms") == null || !socialData.getLoginsAllowed().get("ms")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Microsoft login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.MICROSOFT)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String prefix = "ms_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String tenant = socialData.getProperty(prefix + "tenant"); - String scope = socialData.getProperty(prefix + "scope"); - String token_url = socialData.getProperty(prefix + "token_url"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - boolean login_external_allowed = Boolean - .parseBoolean(socialData.getProperty(prefix + "login_external")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("scope", scope); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("grant_type", "authorization_code"); - params.put("client_secret", clientSecret); - - if (Strings.isNullOrEmpty(token_url)) { - token_url = "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/token"; - } - - AccessToken accessToken = HttpHelperUtility.getAccessToken(token_url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getMicrosoftRedirect(request)); - return null; - } - - accessToken.setProvider(AuthProvider.MICROSOFT); - MicrosoftTokenFiller profiler = new MicrosoftTokenFiller(); - profiler.fillAccessToken(accessToken, null, null, null, null); - if (!login_external_allowed) { - if (accessToken.getName().contains("External")) { - accessToken = null; - throw new IllegalArgumentException("External users are not allowed"); - } - } - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.MICROSOFT)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getMicrosoftRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the Microsoft authorization redirect URL. - * - * @param request inbound HTTP request - * @return Microsoft authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getMicrosoftRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "ms_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String tenant = socialData.getProperty(prefix + "tenant"); - String scope = socialData.getProperty(prefix + "scope"); // need to set this up and reuse - String auth_url = socialData.getProperty(prefix + "auth_url"); - - String state = UUID.randomUUID().toString(); - - if (Strings.isNullOrEmpty(auth_url)) { - auth_url = "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/authorize"; - } - String redirectUrl = auth_url + "?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" - + URLEncoder.encode(redirectUri, UTF8) + "&response_mode=query" + "&scope=" - + URLEncoder.encode(scope, UTF8) + "&state=" + state; - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles Okta OAuth login callback flow. - */ - @GET - @Produces("application/json") - @Path("/login/okta") - public Response loginOkta(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("okta") == null || !socialData.getLoginsAllowed().get("okta")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Okta login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.MICROSOFT)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String prefix = "okta_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String scope = socialData.getProperty(prefix + "scope"); - String token_url = socialData.getProperty(prefix + "token_url"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("scope", scope); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("grant_type", "authorization_code"); - params.put("client_secret", clientSecret); - - AccessToken accessToken = HttpHelperUtility.getAccessToken(token_url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getOktaRedirect(request)); - return null; - } - - accessToken.setProvider(AuthProvider.OKTA); - - // sub is the unique id for a user in okta - String userinfo_url = socialData.getProperty(prefix + "userinfo_url"); - String beanProps = socialData.getProperty(prefix + "beanProps"); - String[] beanPropsArr = beanProps.split(",", -1); - String jsonPattern = socialData.getProperty(prefix + "jsonPattern"); - - OktaTokenFiller profiler = new OktaTokenFiller(); - profiler.fillAccessToken(accessToken, userinfo_url, jsonPattern, beanPropsArr, null); - addAccessToken(accessToken, request, autoAdd); - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.OKTA)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getOktaRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the Okta authorization redirect URL. - * - * @param request inbound HTTP request - * @return Okta authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getOktaRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "okta_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String scope = socialData.getProperty(prefix + "scope"); // need to set this up and reuse - String auth_url = socialData.getProperty(prefix + "auth_url"); - String state = UUID.randomUUID().toString(); - - String redirectUrl = auth_url + "?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" - + URLEncoder.encode(redirectUri, UTF8) + "&response_mode=query" + "&scope=" - + URLEncoder.encode(scope, UTF8) + "&state=" + state; - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - @Path("/login/producthunt") - /** - * Handles Product Hunt OAuth login callback flow. - * - * @param request inbound HTTP request - * @param response outbound HTTP response - * @return redirect response - * @throws IOException when redirect writing fails - */ - public Response loginProducthunt(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("producthunt") == null - || !socialData.getLoginsAllowed().get("producthunt")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Producthunt login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.PRODUCT_HUNT)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String prefix = "producthunt_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("grant_type", "authorization_code"); - params.put("client_secret", clientSecret); - - String url = "https://api.producthunt.com/v1/oauth/token"; - - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getProducthuntRedirect(request)); - return null; - } - accessToken.setProvider(AuthProvider.PRODUCT_HUNT); - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.PRODUCT_HUNT)) { - response.setStatus(302); - response.sendRedirect(getProducthuntRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the Product Hunt authorization redirect URL. - * - * @param request inbound HTTP request - * @return Product Hunt authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getProducthuntRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "producthunt_"; - - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String scope = socialData.getProperty(prefix + "scope"); - - String redirectUrl = "https://api.producthunt.com/v1/oauth/authorize?" + "client_id=" + clientId - + "&response_type=code" + "&redirect_uri=" + URLEncoder.encode(redirectUri, UTF8) + "&scope=" - + URLEncoder.encode(scope, UTF8); - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles Salesforce OAuth login callback flow. - */ - @GET - @Produces("application/json") - @Path("/login/salesforce") - public Response loginSalesforce(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("salesforce") == null - || !socialData.getLoginsAllowed().get("salesforce")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Salesforce login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.SALESFORCE)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String prefix = "salesforce_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("grant_type", "authorization_code"); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("client_secret", clientSecret); - - String url = "https://login.salesforce.com/services/oauth2/token"; - - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getSalesforceRedirect(request)); - return null; - } - accessToken.setProvider(AuthProvider.SALESFORCE); - - // fill the access token with the other properties so we can properly create the - // user - SalesforceTokenFiller profiler = new SalesforceTokenFiller(); - profiler.fillAccessToken(accessToken, null, null, null, null); - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.SALESFORCE)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getSalesforceRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the Salesforce authorization redirect URL. - * - * @param request inbound HTTP request - * @return Salesforce authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getSalesforceRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "salesforce_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - - String redirectUrl = "https://login.salesforce.com/services/oauth2/authorize?" + "client_id=" + clientId - + "&response_type=code" + "&redirect_uri=" + redirectUri + "&scope=" + URLEncoder.encode("api", UTF8); - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles Salesforce OAuth callback flow using dynamic connector credentials. - */ - @GET - @Produces("application/json") - @Path("/login2/salesforce") - public Response loginSalesforceDynamic(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.SALESFORCE)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String state = outputs[1]; - String connectionId = session == null ? null : (String) session.getAttribute("sf_state_" + state); - if (connectionId == null) { - // invalid or tampered state - response.setStatus(400); - return null; - } - session.removeAttribute("sf_state_" + state); - - // get credentials by UUID (ID) from SALESFORCE_CREDENTIALS table - String redirectUri = WebUtility.getCurrentCallbackUrl(request); - boolean autoAdd = true; - - Pair details = SecurityExternalConnectorsUtils - .getSalesforceConnectionDetails(connectionId); - String clientId = details.getValue0(); - String clientSecret = details.getValue1(); - - if (clientId == null || clientSecret == null || redirectUri == null) { - response.setStatus(400); - response.getWriter() - .write("Salesforce credentials not found for connection id = " + connectionId); - return null; - } - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("grant_type", "authorization_code"); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("client_secret", clientSecret); - - String url = "https://login.salesforce.com/services/oauth2/token"; - - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getSalesforceRedirectDynamic(request, response, connectionId)); - return null; - } - accessToken.setProvider(AuthProvider.SALESFORCE); - - // fill the access token with the other properties so we can properly create the - // user - SalesforceTokenFiller profiler = new SalesforceTokenFiller(); - profiler.fillAccessToken(accessToken, null, null, null, null); - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.SALESFORCE)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getSalesforceRedirectDynamic(request, response, null)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the Salesforce dynamic-credential authorization redirect URL. - * - * @param request inbound HTTP request - * @param response outbound HTTP response - * @param connectionId external-connector id - * @return Salesforce authorize URL or {@code null} when validation fails - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - * @throws IOException when response writing fails - */ - private String getSalesforceRedirectDynamic(HttpServletRequest request, @Context HttpServletResponse response, - String connectionId) throws UnsupportedEncodingException, IOException { - String redirectUri = WebUtility.getCurrentCallbackUrl(request); - if (connectionId == null) { - connectionId = request.getParameter("connectionId"); - } - if (connectionId == null || connectionId.isEmpty()) { - response.setStatus(400); - response.getWriter().write("Missing required parameter: connectionId"); - return null; - } - - String state = UUID.randomUUID().toString(); - // store the connection id in session - request.getSession().setAttribute("sf_state_" + state, connectionId); - - Pair details = SecurityExternalConnectorsUtils.getSalesforceConnectionDetails(connectionId); - String clientId = details.getValue0(); - String redirectUrl = "https://login.salesforce.com/services/oauth2/authorize?" + "client_id=" - + URLEncoder.encode(clientId, "UTF-8") + "&response_type=code" + "&redirect_uri=" - + URLEncoder.encode(redirectUri, "UTF-8") + "&scope=" + URLEncoder.encode("api", "UTF-8") + "&state=" - + state; - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles ServiceNow OAuth login callback flow. - */ - @GET - @Produces("application/json") - @Path("/login/servicenow") - public Response loginServiceNow(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("servicenow") == null - || !socialData.getLoginsAllowed().get("servicenow")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Servicenow login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.SERVICENOW)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String prefix = "servicenow_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String instanceUrl = socialData.getProperty(prefix + "instance_url"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("grant_type", "authorization_code"); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("client_secret", clientSecret); - - String url = instanceUrl + "/oauth_token.do"; - - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getServiceNowRedirect(request)); - return null; - } - accessToken.setProvider(AuthProvider.SERVICENOW); - - // fill the access token with the other properties so we can properly create the - // user - ServiceNowTokenFiller profiler = new ServiceNowTokenFiller(); - profiler.fillAccessToken(accessToken, null, null, null, null); - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.SERVICENOW)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getServiceNowRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the ServiceNow authorization redirect URL. - * - * @param request inbound HTTP request - * @return ServiceNow authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getServiceNowRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "servicenow_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String instanceUrl = socialData.getProperty(prefix + "instance_url"); - - String redirectUrl = instanceUrl + "/oauth_auth.do?" + "client_id=" + clientId + "&response_type=code" - + "&redirect_uri=" + redirectUri; - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles ServiceNow OAuth callback flow using dynamic connector credentials. - */ - @GET - @Produces("application/json") - @Path("/login2/servicenow") - public Response loginServiceNowDynamic(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.SERVICENOW)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String state = outputs[1]; - String connectionId = session == null ? null : (String) session.getAttribute("sn_state_" + state); - if (connectionId == null) { - // invalid or tampered state - response.setStatus(400); - return null; - } - session.removeAttribute("sn_state_" + state); - - // get credentials by UUID (ID) from SERVICENOW_CREDENTIALS table - String redirectUri = WebUtility.getCurrentCallbackUrl(request); - boolean autoAdd = true; - - Map details = SecurityExternalConnectorsUtils - .getServiceNowConnectionDetails(connectionId); - String instanceUrl = details.get("instanceUrl"); - String clientId = details.get("clientId"); - String clientSecret = details.get("clientSecret"); - String userInfoUrl = details.get("userProfileUrl"); // to pass to fillAccessToken method - - if (instanceUrl == null || clientId == null || clientSecret == null || redirectUri == null) { - response.setStatus(400); - response.getWriter() - .write("ServiceNow credentials not found for connection id =" + connectionId); - return null; - } - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("grant_type", "authorization_code"); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("client_secret", clientSecret); - - String url = instanceUrl + "/oauth_token.do"; - - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getServiceNowRedirectDynamic(request, response, connectionId)); - return null; - } - accessToken.setProvider(AuthProvider.SERVICENOW); - - // fill the access token with the other properties so we can properly create the - // user - ServiceNowTokenFiller profiler = new ServiceNowTokenFiller(); - profiler.fillAccessToken(accessToken, userInfoUrl, null, null, null); - - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.SERVICENOW)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getServiceNowRedirectDynamic(request, response, null)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the ServiceNow dynamic-credential authorization redirect URL. - * - * @param request inbound HTTP request - * @param response outbound HTTP response - * @param connectionId external-connector id - * @return ServiceNow authorize URL or {@code null} when validation fails - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - * @throws IOException when response writing fails - */ - private String getServiceNowRedirectDynamic(HttpServletRequest request, @Context HttpServletResponse response, - String connectionId) throws UnsupportedEncodingException, IOException { - String redirectUri = WebUtility.getCurrentCallbackUrl(request); - if (connectionId == null) { - connectionId = request.getParameter("connectionId"); - } - if (connectionId == null || connectionId.isEmpty()) { - response.setStatus(400); - response.getWriter().write("Missing required parameter: connectionId"); - return null; - } - - String state = UUID.randomUUID().toString(); - // store the connection id in session - request.getSession().setAttribute("sn_state_" + state, connectionId); - - Map details = SecurityExternalConnectorsUtils.getServiceNowConnectionDetails(connectionId); - String instanceUrl = details.get("instanceUrl"); - String clientId = details.get("clientId"); - - String redirectUrl = instanceUrl + "/oauth_auth.do?" + "client_id=" + URLEncoder.encode(clientId, "UTF-8") - + "&response_type=code" + "&redirect_uri=" + URLEncoder.encode(redirectUri, "UTF-8") + "&state=" - + state; - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles SiteMinder OAuth login callback flow. - */ - @GET - @Produces("application/json") - @Path("/login/siteminder") - public Response loginSiteminder(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("siteminder") == null - || !socialData.getLoginsAllowed().get("siteminder")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Siteminder login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.SITEMINDER)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String prefix = "siteminder_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String tenant = socialData.getProperty(prefix + "tenant"); - String scope = socialData.getProperty(prefix + "scope"); - String token_url = socialData.getProperty(prefix + "token_url"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("scope", scope); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("grant_type", "authorization_code"); - params.put("client_secret", clientSecret); - - if (Strings.isNullOrEmpty(token_url)) { - token_url = "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/token"; - } - AccessToken accessToken = HttpHelperUtility.getAccessToken(token_url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getSiteminderRedirect(request)); - return null; - } - - accessToken.setProvider(AuthProvider.SITEMINDER); - addAccessToken(accessToken, request, autoAdd); - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.SITEMINDER)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getSiteminderRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the SiteMinder authorization redirect URL. - * - * @param request inbound HTTP request - * @return SiteMinder authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getSiteminderRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "siteminder_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String tenant = socialData.getProperty(prefix + "tenant"); - String scope = socialData.getProperty(prefix + "scope"); // need to set this up and reuse - String auth_url = socialData.getProperty(prefix + "auth_url"); - String state = UUID.randomUUID().toString(); - - if (Strings.isNullOrEmpty(auth_url)) { - auth_url = "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/authorize"; - } - - String redirectUrl = auth_url + "?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" - + URLEncoder.encode(redirectUri, UTF8) + "&response_mode=query" + "&scope=" - + URLEncoder.encode(scope, UTF8) + "&state=" + state; - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles SurveyMonkey OAuth login callback flow. - */ - @GET - @Produces("application/json") - @Path("/login/surveymonkey") - public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("surveymonkey") == null - || !socialData.getLoginsAllowed().get("surveymonkey")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Surveymonkey login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.SURVEYMONKEY)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String prefix = "surveymonkey_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("grant_type", "authorization_code"); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("client_secret", clientSecret); - - String url = "https://api.surveymonkey.com/oauth/token"; - - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getSurveyMonkeyRedirect(request)); - return null; - } - accessToken.setProvider(AuthProvider.SURVEYMONKEY); - MonkeyProfile.fillAccessToken(accessToken, null); - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.SURVEYMONKEY)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getSurveyMonkeyRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the SurveyMonkey authorization redirect URL. - * - * @param request inbound HTTP request - * @return SurveyMonkey authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getSurveyMonkeyRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "surveymonkey_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - - String redirectUrl = "https://api.surveymonkey.com/oauth/authorize?" + "client_id=" + clientId - + "&response_type=code" + "&redirect_uri=" + redirectUri; - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles Twitter OAuth login callback flow. - * - * @param request - * @param response - * @return - * @throws IOException - */ - @GET - @Produces("application/json") - @Path("/login/twitter") - public Response loginTwitter(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws IOException { - if (socialData.getLoginsAllowed().get("twitter") == null || !socialData.getLoginsAllowed().get("twitter")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "Twitter login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - // getting the bearer token on twitter for app authentication is a lot simpler - // need to just combine the id and secret - // base 64 and send as authorization - - // https://developer.github.com/apps/building-oauth-apps/authorization-options-for-oauth-apps/ - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, AuthProvider.GITHUB)) { - - String[] outputs = HttpHelperUtility.getCodes(queryString); - // oauth code and state should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.5 - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - String state = URLDecoder.decode(outputs[1], StandardCharsets.UTF_8); - if (code.matches("[ -~]+") && state.matches("[ -~]+")) { - String prefix = "twitter_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("state", state); - params.put("client_secret", clientSecret); - - String url = "https://api.twitter.com/oauth/access_token"; - - AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, false, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getTwitterRedirect(request)); - return null; - } - - accessToken.setProvider(AuthProvider.TWITTER); - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, AuthProvider.TWITTER)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getTwitterRedirect(request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the Twitter authorization redirect URL. - * - * @param request inbound HTTP request - * @return Twitter authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getTwitterRedirect(HttpServletRequest request) throws UnsupportedEncodingException { - String prefix = "twitter_"; - - String clientId = socialData.getProperty(prefix + "client_id"); - // String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - String scope = socialData.getProperty(prefix + "scope"); - String nonce = UUID.randomUUID().toString(); - String timestamp = System.currentTimeMillis() + ""; - - StringBuffer signatureString = new StringBuffer("GET").append("&"); - signatureString.append(URLEncoder.encode("https://api.twitter.com/oauth/authorize", UTF8)).append("&"); - - StringBuffer parameterString = new StringBuffer(""); - parameterString.append("oauth_callback=").append(URLEncoder.encode(redirectUri, UTF8)).append("&"); - parameterString.append("oauth_consumer_key=").append(clientId).append("&"); - parameterString.append("oauth_nonce=").append(nonce).append("&"); - parameterString.append("oauth_timestamp=").append(timestamp); - - // String finalString = signatureString.toString() + parameterString.toString(); - - // String signature = - - String redirectUrl = "https://github.com/login/oauth/authorize?" + "oauth_consumer_key=" + clientId - + "&oauth_callback=" + redirectUri + "&oauth_nonce=" + nonce + "&oauth_timestamp=" + timestamp - + "&scope=" + URLEncoder.encode(scope, UTF8); - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - /** - * Handles OAuth login callback flow for a generic provider. - */ - @GET - @Produces("application/json") - @Path("/login/{provider}") - public Response loginGeneric(@PathParam("provider") String provider, @Context HttpServletRequest request, - @Context HttpServletResponse response) throws IOException { - provider = WebUtility.inputSanitizer(provider); - if (socialData.getLoginsAllowed().get(provider) == null || !socialData.getLoginsAllowed().get(provider)) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, provider + " login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - AuthProvider providerEnum = AuthProvider.getProviderFromString(provider.toUpperCase()); - - HttpSession session = initializeOAuthLoginSession(request); - User userObj = getSessionUser(session); - String queryString = getEncodedQueryString(request); - if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, providerEnum)) { - String[] outputs = HttpHelperUtility.getCodes(queryString); - - // oauth code should match [ -~]+ (1 or more ascii) - // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 - String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); - if (code.matches("[ -~]+")) { - String prefix = provider + "_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String clientSecret = socialData.getProperty(prefix + "secret_key"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); - // String tenant = socialData.getProperty(prefix + "tenant"); - - // removing scope for now as it isn't needed in token call usually - // String scope = socialData.getProperty(prefix + "scope"); - String token_url = socialData.getProperty(prefix + "token_url"); - - classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); - - Map params = new HashMap<>(); - params.put("client_id", clientId); - // params.put("scope", scope); - params.put("redirect_uri", redirectUri); - params.put("code", code); - params.put("grant_type", "authorization_code"); - params.put("client_secret", clientSecret); - - if (Strings.isNullOrEmpty(token_url)) { - throw new IllegalArgumentException("Token URL can not be null or empty"); - } - - AccessToken accessToken = HttpHelperUtility.getAccessToken(token_url, params, true, true); - if (accessToken == null) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getGenericRedirect(provider, request)); - return null; - } - - String userInfoURL = socialData.getProperty(prefix + "userinfo_url"); - // "name","id","email" - String beanProps = socialData.getProperty(prefix + "beanProps"); - String[] beanPropsArr = beanProps.split(",", -1); - String jsonPattern = socialData.getProperty(prefix + "jsonPattern"); - - accessToken.setProvider(providerEnum); - - // this is a check for sanitizing a response back from an IAM provider - not - // common and should be false - // examples would be unescaped special chars in the response that then can't be - // parsed into a json. - // this is not very common. - boolean sanitizeResponse = Boolean - .parseBoolean(socialData.getProperty(prefix + "sanitizeUserResponse")); - - GenericTokenFiller profiler = new GenericTokenFiller(); - profiler.fillAccessToken(accessToken, userInfoURL, jsonPattern, beanPropsArr, null, - sanitizeResponse); - - if (Boolean.parseBoolean(socialData.getProperty(prefix + "groups"))) { - // get groups - String group_url = socialData.getProperty(prefix + "group_url"); - // make the call to get the groups - String groupsJson = HttpHelperUtility.makeGetCall(group_url, accessToken.getAccess_token()); - // this is a check for sanitizing a response back from an IAM provider - not - // common and should be false - // examples would be unescaped special chars in the response that then can't be - // parsed into a json. - boolean sanitizeGroupResponse = Boolean - .parseBoolean(socialData.getProperty(prefix + "sanitizeGroupResponse")); - if (sanitizeGroupResponse) { - groupsJson = groupsJson.replace("\\", "\\\\"); - // add more replacements as need be in the future - } - - Set userGroups = new HashSet(); - // are groups returned as a single string or an array in a json. Usually it is - // an array in a json. - boolean groupStringResponse = Boolean - .parseBoolean(socialData.getProperty(prefix + "group_string_return")); - if (groupStringResponse) { - // this json pattern should return a single string with groups concat - // ""fakeGroups":"CN=group1, CN=group2, CN=group3" - String groupJsonPattern = socialData.getProperty(prefix + "groupJsonPattern"); - JsonNode result = BeanFiller.getJmesResult(groupsJson, groupJsonPattern); - try { - // get the single string and the regex pattern. validate the pattern - String groupText = result.asText(); - String regexPattern = socialData.getProperty(prefix + "group_string_regex"); - try { - Pattern pattern = Pattern.compile(regexPattern); - } catch (PatternSyntaxException e) { - classLogger.error("Unexpected error in loginGeneric", e); - throw new SemossPixelException("Pattern input is not a valid regex"); - } - - // split the groups - String[] groups = groupText.split(regexPattern); - for (String group : groups) { - userGroups.add(group); - } - } catch (Exception e) { - classLogger.error("Unexpected error in loginGeneric", e); - throw new SemossPixelException("Could not parse response as string"); - } - - } else { - // this json pattern should return an array - String groupJsonPattern = socialData.getProperty(prefix + "groupJsonPattern"); - JsonNode result = BeanFiller.getJmesResult(groupsJson, groupJsonPattern); - if ((result instanceof ArrayNode) && result.get(0) instanceof ObjectNode) { - throw new SemossPixelException( - "Group result must return flat array. Please check groupJsonPatter"); - } - for (int inputIndex = 0; result != null && inputIndex < result.size(); inputIndex++) { - String thisInput = result.get(inputIndex).asText(); - userGroups.add(thisInput); - } - } - - accessToken.setUserGroups(userGroups); - accessToken.setUserGroupType(providerEnum.toString()); - } - - addAccessToken(accessToken, request, autoAdd); - - classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); - } - } - } - - userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, providerEnum)) { - // not authenticated - response.setStatus(302); - response.sendRedirect(getGenericRedirect(provider, request)); - return null; - } - - setMainPageRedirect(request, response); - return null; - } - - /** - * Builds the generic provider authorization redirect URL. - * - * @param provider provider key from social properties - * @param request inbound HTTP request - * @return provider authorize URL - * @throws UnsupportedEncodingException when redirect parameters cannot be URL - * encoded - */ - private String getGenericRedirect(String provider, HttpServletRequest request) throws UnsupportedEncodingException { - provider = WebUtility.inputSanitizer(provider); - String prefix = provider + "_"; - String clientId = socialData.getProperty(prefix + "client_id"); - String redirectUri = socialData.getProperty(prefix + "redirect_uri"); - // String tenant = socialData.getProperty(prefix + "tenant"); - String scope = socialData.getProperty(prefix + "scope"); // need to set this up and reuse - String auth_url = socialData.getProperty(prefix + "auth_url"); - - String state = UUID.randomUUID().toString(); - - if (Strings.isNullOrEmpty(auth_url)) { - throw new IllegalArgumentException("Authorize URL can not be null or empty"); - } - - String redirectUrl; - - // are you already adding custom props? if so I will skip adding the ? - if (auth_url.contains("?")) { - redirectUrl = auth_url + "&client_id=" + clientId + "&response_type=code" + "&redirect_uri=" - + URLEncoder.encode(redirectUri, UTF8) + "&response_mode=query" + "&scope=" - + URLEncoder.encode(scope, UTF8) + "&state=" + state; - } else { - redirectUrl = auth_url + "?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" - + URLEncoder.encode(redirectUri, UTF8) + "&response_mode=query" + "&scope=" - + URLEncoder.encode(scope, UTF8) + "&state=" + state; - } - - classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); - return redirectUrl; - } - - ///////////////////////////////////////////////////////////////// - - /** - * This portion of code is for semoss generated users - */ - - /** - * Authenticates a native user with username and password credentials. - * - * @param request - * @return true if the information provided to log in is valid otherwise error. - */ - @POST - @Produces("application/json") - @Path("/login") - public Response loginNative(@Context HttpServletRequest request, @Context HttpServletResponse response) { - Map ret = new HashMap<>(); - - if (socialData.getLoginsAllowed().get("native") == null || !socialData.getLoginsAllowed().get("native")) { - ret.put(Constants.ERROR_MESSAGE, "Native login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - try { - String username = WebUtility.inputSQLSanitizer(request.getParameter("username")); - String password = WebUtility.inputSQLSanitizer(request.getParameter("password")); - String redirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); - // so that the default is to redirect - Boolean disableRedirect = Boolean.parseBoolean(request.getParameter("disableRedirect") + ""); - - if (username == null || password == null || username.isEmpty() || password.isEmpty()) { - classLogger.warn("User is trying to login using username='{}' but user name or password are empty", - username); - ret.put(Constants.ERROR_MESSAGE, "The user name or password are empty"); - return WebUtility.getResponse(ret, 401); - } - - boolean canLogin = SecurityNativeUserUtils.logIn(username, password); - if (canLogin) { - String name = SecurityNativeUserUtils.getNameUser(username); - String email = SecurityNativeUserUtils.getUserEmail(username); - - String id = SecurityNativeUserUtils.getUserId(username); - AccessToken authToken = new AccessToken(); - authToken.setProvider(AuthProvider.NATIVE); - authToken.setId(id); - authToken.setName(name); - authToken.setUsername(username); - authToken.setEmail(email); - // no need to auto-add since to login native you must already exist - addAccessToken(authToken, request, false); - - // add these to the return - ret.put("success", "true"); - ret.put("username", username); - ret.put("name", name); - ret.put("email", email); - - // log the log in - if (!disableRedirect) { - setMainPageRedirect(request, response, redirect); - } - } else { - HttpSession session = request.getSession(false); - User user = null; - if (session != null) { - user = (User) session.getAttribute(Constants.SESSION_USER); - if (!AbstractSecurityUtils.anonymousUsersEnabled() && user != null && user.getLogins().isEmpty()) { - session.invalidate(); - } - } - classLogger.warn("User is trying to login using username='{}' but user name or password are empty", - username); - ret.put(Constants.ERROR_MESSAGE, "The user name or password are invalid."); - return WebUtility.getResponse(ret, 401); - } - } catch (Exception e) { - HttpSession session = request.getSession(false); - if (session != null) { - User user = (User) session.getAttribute(Constants.SESSION_USER); - if (!AbstractSecurityUtils.anonymousUsersEnabled() && user != null && user.getLogins().isEmpty()) { - session.invalidate(); - } - } - classLogger.error("Unexpected error in loginNative", e); - ret.put(Constants.ERROR_MESSAGE, "An unexpected error happened. Please try again."); - return WebUtility.getResponse(ret, 500); - } - - return WebUtility.getResponse(ret, 200); - } - - /** - * Authenticates a user with LDAP credentials. - * - * @param request - * @return true if the information provided to log in is valid otherwise error. - */ - @POST - @Produces("application/json") - @Path("/loginLDAP") - public Response loginLDAP(@Context HttpServletRequest request, @Context HttpServletResponse response) { - Map ret = new HashMap<>(); - if (socialData.getLoginsAllowed().get("ldap") == null || !socialData.getLoginsAllowed().get("ldap")) { - ret.put(Constants.ERROR_MESSAGE, "LDAP login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - ILdapAuthenticator authenticator = null; - try { - String username = WebUtility.inputSQLSanitizer(request.getParameter("username")); - String password = WebUtility.inputSQLSanitizer(request.getParameter("password")); - // so that the default is to redirect - Boolean disableRedirect = Boolean.parseBoolean(request.getParameter("disableRedirect") + ""); - - if (username == null || password == null || username.isEmpty() || password.isEmpty()) { - ret.put(Constants.ERROR_MESSAGE, "The user name or password are empty"); - return WebUtility.getResponse(ret, 401); - } - - authenticator = socialData.getLdapAuthenticator(); - AccessToken authToken = authenticator.authenticate(username, password); - if (authToken == null) { - throw new IllegalArgumentException("Unable to parse any user attributes"); - } - boolean autoAdd = Boolean - .parseBoolean(socialData.getProperty(ILdapAuthenticator.LDAP + "auto_add", "true")); - addAccessToken(authToken, request, autoAdd); - ret.put("success", "true"); - ret.put("username", username); - // log the log in - if (!disableRedirect) { - setMainPageRedirect(request, response); - } - } catch (LDAPPasswordChangeRequiredException e) { - HttpSession session = request.getSession(false); - if (session != null) { - User user = (User) session.getAttribute(Constants.SESSION_USER); - if (!AbstractSecurityUtils.anonymousUsersEnabled() && user != null && user.getLogins().isEmpty()) { - session.invalidate(); - } - } - classLogger.error("Unexpected error in loginLDAP", e); - ret.put(Constants.ERROR_MESSAGE, "User must change their password before login"); - ret.put(ILdapAuthenticator.LDAP_PASSWORD_CHANGE_RETURN_KEY, true); - return WebUtility.getResponse(ret, 401); - } catch (Exception e) { - HttpSession session = request.getSession(false); - if (session != null) { - User user = (User) session.getAttribute(Constants.SESSION_USER); - if (!AbstractSecurityUtils.anonymousUsersEnabled() && user != null && user.getLogins().isEmpty()) { - session.invalidate(); - } - } - classLogger.error("Unexpected error in loginLDAP", e); - ret.put(Constants.ERROR_MESSAGE, e.getMessage()); - return WebUtility.getResponse(ret, 500); - } finally { - if (authenticator != null) { - try { - authenticator.close(); - } catch (IOException e) { - classLogger.error("Unexpected error in loginLDAP", e); - } - } - } - - return WebUtility.getResponse(ret, 200); - } - - /** - * Changes an Active Directory user password. - * - * @param request - * @return true if the information provided to log in is valid otherwise error. - */ - @POST - @Produces("application/json") - @Path("/changeADPassword") - public Response changeADPassword(@Context HttpServletRequest request, @Context HttpServletResponse response) { - Map ret = new HashMap<>(); - if ((socialData.getLoginsAllowed().get("ldap") == null || !socialData.getLoginsAllowed().get("ldap")) - && !Boolean.parseBoolean(socialData.getProperty("linotp_check_ad", "false"))) { - ret.put(Constants.ERROR_MESSAGE, "LDAP change password is not allowed/configured"); - return WebUtility.getResponse(ret, 400); - } - - ILdapAuthenticator authenticator = null; - try { - String username = WebUtility.inputSQLSanitizer(request.getParameter("username")); - String curPassword = WebUtility.inputSQLSanitizer(request.getParameter("curPassword")); - String newPassword = WebUtility.inputSQLSanitizer(request.getParameter("newPassword")); - - if (username == null || curPassword == null || newPassword == null || username.isEmpty() - || curPassword.isEmpty() || newPassword.isEmpty()) { - ret.put(Constants.ERROR_MESSAGE, "The user name, current password, or new password are empty"); - return WebUtility.getResponse(ret, 401); - } - - authenticator = socialData.getLdapAuthenticator(); - authenticator.updateUserPassword(username, curPassword, newPassword); - ret.put("success", "true"); - ret.put("username", username); - return WebUtility.getResponse(ret, 200); - } catch (Exception e) { - HttpSession session = request.getSession(false); - if (session != null) { - User user = (User) session.getAttribute(Constants.SESSION_USER); - if (!AbstractSecurityUtils.anonymousUsersEnabled() && user != null && user.getLogins().isEmpty()) { - session.invalidate(); - } - } - classLogger.error("Unexpected error in changeADPassword", e); - ret.put(Constants.ERROR_MESSAGE, e.getMessage()); - return WebUtility.getResponse(ret, 500); - } finally { - if (authenticator != null) { - try { - authenticator.close(); - } catch (IOException e) { - classLogger.error("Unexpected error in changeADPassword", e); - } - } - } - } - - /** - * Authenticates a user by validating LinOTP one-time passcodes. - * - * @param request - * @return true if the information provided to log in is valid otherwise error. - * @throws IOException - * @throws ClientProtocolException - */ - @POST - @Produces("application/json") - @Path("/loginLinOTP") - public Response loginLinOTP(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws ClientProtocolException, IOException { - Map returnMap = new HashMap<>(); - if (socialData.getLoginsAllowed().get("linotp") == null || !socialData.getLoginsAllowed().get("linotp")) { - returnMap.put(Constants.ERROR_MESSAGE, "LinOTP login is not allowed"); - return WebUtility.getResponse(returnMap, 400); - } - - String redirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); - // so that the default is to redirect - Boolean disableRedirect = Boolean.parseBoolean(request.getParameter("disableRedirect") + ""); - boolean autoAdd = Boolean.parseBoolean(socialData.getProperty("linotp_auto_add", "true")); - - LinOTPResponse linotpResponse = LinOTPUtil.login(request); - returnMap = linotpResponse.getReturnMap(); - int responseCode = linotpResponse.getResponseCode(); - if (responseCode != 200) { - // we just throw the error - return WebUtility.getResponse(returnMap, responseCode); - } else { - // are we logged in? - AccessToken token = linotpResponse.getToken(); - if (token == null) { - // it is a 200 but we are not logged in - // you likely need to enter otp in 2nd response - return WebUtility.getResponse(returnMap, responseCode); - } - - // we have a login - addAccessToken(token, request, autoAdd); - // log the log in - if (!disableRedirect) { - setMainPageRedirect(request, response, redirect); - } - - return WebUtility.getResponse(returnMap, 200); - } - - } - - /** - * Resets LinOTP failed-attempt counters for a user. - * - * @param request - * @return true if the information provided to log in is valid otherwise error. - * @throws IOException - * @throws ClientProtocolException - */ - @POST - @Produces("application/json") - @Path("/resetLinOTPFailCounter") - public Response resetLinOTPFailCounter(@Context HttpServletRequest request, @Context HttpServletResponse response) - throws ClientProtocolException, IOException { - try { - LinOTPResponse linotpResponse = LinOTPUtil.resetCounter(request); - Map returnMap = linotpResponse.getReturnMap(); - int responseCode = linotpResponse.getResponseCode(); - // this is simple, take response code and message and return - return WebUtility.getResponse(returnMap, responseCode); - } catch (Exception e) { - classLogger.error("Unexpected error in resetLinOTPFailCounter", e); - Map errorMessage = new HashMap<>(); - errorMessage.put(Constants.ERROR_MESSAGE, - "Error occurred resetting the pin. Error message = " + e.getMessage()); - return WebUtility.getResponse(errorMessage, 500); - } - } - - /** - * Creates a native platform user. email) - * - * @param request - * @return true if the user is created otherwise error. - */ - @POST - @Produces("application/json") - @Path("createUser") - public Response createNativeUser(@Context HttpServletRequest request) { - Map ret = new HashMap<>(); - - if (socialData.getLoginsAllowed().get("native") == null || !socialData.getLoginsAllowed().get("native")) { - ret.put(Constants.ERROR_MESSAGE, "Native login is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - if (socialData.getLoginsAllowed().get("registration") == null - || !socialData.getLoginsAllowed().get("registration")) { - ret.put(Constants.ERROR_MESSAGE, "Native registration is not allowed"); - return WebUtility.getResponse(ret, 400); - } - - // get the connection to RDF_MAP.prop file to get the user default set values - try { - // Note - for native users - // the id and the username are always the same - String username = WebUtility.inputSQLSanitizer(request.getParameter("username")); - String name = WebUtility.inputSQLSanitizer(request.getParameter("name")); - String password = WebUtility.inputSQLSanitizer(request.getParameter("password")); - String email = WebUtility.inputSQLSanitizer(request.getParameter("email")); - String phone = WebUtility.inputSanitizer(request.getParameter("phone")); - String phoneExtension = WebUtility.inputSanitizer(request.getParameter("phoneextension")); - String countryCode = WebUtility.inputSanitizer(request.getParameter("countrycode")); - - String modelUsageRestriction = WebUtility.inputSanitizer(request.getParameter("modelUsageRestriction")); - if (modelUsageRestriction != null) { - modelUsageRestriction = modelUsageRestriction.trim(); - } - String modelUsageFrequency = WebUtility.inputSanitizer(request.getParameter("modelUsageFrequency")); - if (modelUsageFrequency != null) { - modelUsageFrequency = modelUsageFrequency.trim(); - } - int modelMaxTokens = 0; - String modelMaxTokensStr = WebUtility.inputSanitizer(request.getParameter("modelMaxTokens")); - if (modelMaxTokensStr != null && !(modelMaxTokensStr = modelMaxTokensStr.trim()).isEmpty()) { - // must be a valid integer - try { - modelMaxTokens = Integer.parseInt(modelMaxTokensStr); - } catch (NumberFormatException e) { - classLogger.error("Unexpected error in createNativeUser", e); - ret.put(Constants.ERROR_MESSAGE, "modelMaxTokens must be a valid integer value"); - return WebUtility.getResponse(ret, 400); - } - } - double modelMaxResponseTime = 0.0; - String modelMaxResponseTimeStr = WebUtility.inputSanitizer(request.getParameter("modelMaxResponseTime")); - if (modelMaxResponseTimeStr != null - && !(modelMaxResponseTimeStr = modelMaxResponseTimeStr.trim()).isEmpty()) { - // must be a valid double - try { - modelMaxResponseTime = Double.parseDouble(modelMaxResponseTimeStr); - } catch (NumberFormatException e) { - classLogger.error("Unexpected error in createNativeUser", e); - ret.put(Constants.ERROR_MESSAGE, "modelMaxResponseTime must be a valid double value"); - return WebUtility.getResponse(ret, 400); - } - } - AccessToken newUser = new AccessToken(); - - newUser.setProvider(AuthProvider.NATIVE); - newUser.setId(username); - newUser.setUsername(username); - newUser.setEmail(email); - newUser.setName(name); - newUser.setPhone(phone); - newUser.setPhoneExtension(phoneExtension); - newUser.setCountryCode(countryCode); - // model restriction values - newUser.setModelUsageRestriction(modelUsageRestriction); - newUser.setModelUsageFrequency(modelUsageFrequency); - newUser.setModelMaxTokens(modelMaxTokens); - newUser.setModelMaxResponseTime(modelMaxResponseTime); - - boolean userCreated = SecurityNativeUserUtils.addNativeUser(newUser, password); - if (userCreated) { - ret.put("success", "true"); - ret.put("username", username); - return WebUtility.getResponse(ret, 200); - } else { - ret.put(Constants.ERROR_MESSAGE, "The user name or email aready exists."); - return WebUtility.getResponse(ret, 400); - } - } catch (IllegalArgumentException iae) { - classLogger.error("Unexpected error in createNativeUser", iae); - ret.put(Constants.ERROR_MESSAGE, iae.getMessage()); - return WebUtility.getResponse(ret, 500); - } catch (Exception e) { - classLogger.error("Unexpected error in createNativeUser", e); - ret.put(Constants.ERROR_MESSAGE, "An unexpected error happened. Please try again."); - return WebUtility.getResponse(ret, 500); - } - } - - /** - * Creates an API user credential. email) - * - * @param request - * @return true if the user is created otherwise error. - */ - @POST - @Produces("application/json") - @Path("createAPIUser") - public Response createAPIUser(@Context HttpServletRequest request) { - if (socialData.getLoginsAllowed().get("api_user") == null || !socialData.getLoginsAllowed().get("api_user")) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "API User is not allowed for login"); - return WebUtility.getResponse(ret, 400); - } - - if (Utility.getApplicationAdminOnlyCreateAPIUser()) { - User user = (User) request.getSession().getAttribute(Constants.SESSION_USER); - if (user == null) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "No active session. Please login as an admin"); - return WebUtility.getResponse(ret, 401); - } - if (!SecurityAdminUtils.userIsAdmin(user)) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, - "User is not an admin and does not have access. Please login as an admin"); - return WebUtility.getResponse(ret, 401); - } - } - - String name = WebUtility.inputSQLSanitizer(request.getParameter("name")); - Map oneTimeDetails = SecurityAPIUserUtils.createAPIUser(name); - return WebUtility.getResponse(oneTimeDetails, 200); - } - - ////////////////////////////////////////////////////////////////////// - - /** - * Returns the map of enabled and disabled login providers. the FE - */ - - @GET - @Produces("application/json") - @Path("/loginsAllowed/") - public Response loginsAllowed(@Context HttpServletRequest request) { - return WebUtility.getResponse(socialData.getLoginsAllowed(), 200); - } - - /** - * Returns provider property values from social properties for admin users. - * - * @param request inbound HTTP request - * @return login-property map grouped by provider - */ - @GET - @Produces("application/json") - @Path("/loginProperties/") - public Response loginProperties(@Context HttpServletRequest request) { - User user = (User) request.getSession().getAttribute(Constants.SESSION_USER); - if (user == null) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "No user defined to access properties. Please login as an admin"); - return WebUtility.getResponse(ret, 401); - } - if (!SecurityAdminUtils.userIsAdmin(user)) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, "User is not an admin and does not have access. Please login as an admin"); - return WebUtility.getResponse(ret, 401); - } - - // you have access - lets send all the info - - Map> loginApps = new TreeMap<>(); - - Set propSet = socialData.stringPropertyNames(); - for (String prop : propSet) { - if (!prop.contains("_")) { - // bad format - // ignore - continue; - } - String[] split = prop.toString().split("_", 2); - String type = split[0]; - String type_key = split[1]; - - if (!loginApps.containsKey(type)) { - loginApps.put(type, new TreeMap()); - } - - loginApps.get(type).put(type_key, socialData.getProperty(prop)); - } - - return WebUtility.getResponse(loginApps, 200); - } - - /** - * Updates social properties for one provider. - * - * @param provider provider key - * @param form form payload containing serialized modifications - * @param request inbound HTTP request - * @return operation result - */ - @POST - @Produces("application/json") - @Path("/modifyLoginProperties/{provider}") - public synchronized Response modifyLoginProperties(@PathParam("provider") String provider, - MultivaluedMap form, @Context HttpServletRequest request) { - - provider = WebUtility.inputSanitizer(provider); - - User user = (User) request.getSession().getAttribute(Constants.SESSION_USER); - if (user == null) { - return WebUtility.getResponse("No user defined to access properties. Please login as an admin", 400); - } - if (!SecurityAdminUtils.userIsAdmin(user)) { - return WebUtility.getResponse("User is not an admin and does not have access. Please login as an admin", - 400); - } - - Gson gson = new Gson(); - Map mods = gson.fromJson(form.getFirst("modifications"), new TypeToken>() { - }.getType()); - Map sanitizedMods = new HashMap<>(); - - for (String key : mods.keySet()) { - sanitizedMods.put(WebUtility.inputSanitizer(key), WebUtility.inputSanitizer(mods.get(key))); - } - - try { - socialData.updateSocialProperties(provider, sanitizedMods); - } catch (Exception e) { - classLogger.error("Unexpected error in modifyLoginProperties", e); - Map errorRet = new HashMap<>(); - errorRet.put(Constants.ERROR_MESSAGE, e.getMessage()); - return WebUtility.getResponse(errorRet, 500); - } - - return WebUtility.getResponse(true, 200); - } - - /** - * Replaces all social properties content. - * - * @param request inbound HTTP request - * @return operation result - */ - @POST - @Produces("application/json") - @Path("/modifyAllLoginProperties") - public synchronized Response modifyAllLoginProperties(@Context HttpServletRequest request) { - User user = (User) request.getSession().getAttribute(Constants.SESSION_USER); - if (user == null) { - return WebUtility.getResponse("No user defined to access properties. Please login as an admin", 400); - } - if (!SecurityAdminUtils.userIsAdmin(user)) { - return WebUtility.getResponse("User is not an admin and does not have access. Please login as an admin", - 400); - } - - String newSocialProperties = request.getParameter("socialProperties"); - try { - socialData.updateAllProperties(newSocialProperties); - } catch (Exception e) { - classLogger.error("Unexpected error in modifyAllLoginProperties", e); - Map errorRet = new HashMap<>(); - errorRet.put(Constants.ERROR_MESSAGE, e.getMessage()); - return WebUtility.getResponse(errorRet, 500); - } - - return WebUtility.getResponse(true, 200); - } - - /** - * Returns the full raw social-properties file content for admin users. - * - * @param request inbound HTTP request - * @return social-properties content response - */ - @GET - @Produces("application/json") - @Path("/getAllLoginProperties") - public synchronized Response getAllLoginProperties(@Context HttpServletRequest request) { - User user = (User) request.getSession().getAttribute(Constants.SESSION_USER); - if (user == null) { - return WebUtility.getResponse("No user defined to access properties. Please login as an admin", 400); - } - if (!SecurityAdminUtils.userIsAdmin(user)) { - return WebUtility.getResponse("User is not an admin and does not have access. Please login as an admin", - 400); - } - - try { - String fileContent = socialData.getFileContents(); - Map retMap = new HashMap<>(); - retMap.put("content", fileContent); - return WebUtility.getResponse(retMap, 200); - } catch (Exception e) { - classLogger.error("Unexpected error in getAllLoginProperties", e); - Map errorRet = new HashMap<>(); - errorRet.put(Constants.ERROR_MESSAGE, e.getMessage()); - return WebUtility.getResponse(errorRet, 500); - } - } - - /** - * Redirects a successful login to the main app page or a stored custom - * redirect. - * - * @param request inbound HTTP request - * @param response outbound HTTP response - */ - private void setMainPageRedirect(@Context HttpServletRequest request, @Context HttpServletResponse response) { - String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); - if (customRedirect == null || customRedirect.isEmpty()) { - customRedirect = (String) request.getSession().getAttribute(CUSTOM_REDIRECT_SESSION_KEY); - // also remove the attribute so additional logins dont do the redirect as well - request.getSession().removeAttribute(CUSTOM_REDIRECT_SESSION_KEY); - } - setMainPageRedirect(request, response, customRedirect); - } - - /** - * Redirects a successful login to the requested destination. - * - * @param request inbound HTTP request - * @param response outbound HTTP response - * @param customRedirect explicit redirect URL when provided - */ - private void setMainPageRedirect(@Context HttpServletRequest request, @Context HttpServletResponse response, - String customRedirect) { - // see if we have a location to redirect the user - // if so, we will send them back to that URL - // otherwise, we send them back to the FE - HttpSession session = request.getSession(); - String contextPath = request.getContextPath(); - - boolean useCustom = customRedirect != null && !customRedirect.isEmpty(); - boolean endpoint = session.getAttribute(Constants.ENDPOINT_REDIRECT_KEY) != null; - response.setStatus(302); - try { - boolean secureRequest = "https".equalsIgnoreCase(WebUtility.getProtocol(request)); - // add the cookie to the header directly - // to allow for cross site login when embedded as iframe - String setCookieString = DBLoader.getSessionIdKey() + "=" + session.getId() + "; Path=" + contextPath - + "; HttpOnly" - + ((ClusterUtil.IS_CLUSTER || secureRequest) - ? ("; Secure; SameSite=" + Utility.getSameSiteCookieValue()) - : ""); - response.addHeader("Set-Cookie", setCookieString); - if (useCustom) { - response.addHeader("redirect", customRedirect); - String encodedCustomRedirect = Encode.forHtml(customRedirect); - response.sendError(302, "Need to redirect to " + encodedCustomRedirect); - } else if (endpoint) { - String redirectUrl = session.getAttribute(Constants.ENDPOINT_REDIRECT_KEY) + ""; - response.addHeader("redirect", redirectUrl); - response.sendError(302, "Need to redirect to " + redirectUrl); - } else { - response.sendRedirect(socialData.getProperty("redirect")); - } - } catch (IOException e) { - classLogger.error("Unexpected error in setMainPageRedirect", e); - } - } - - ////////////////////////////////////////////////////////////////////// - - /** - * Returns servlet-container principal details for the current request. - * - * @param request inbound HTTP request - * @param response outbound HTTP response - * @return principal and group metadata payload - */ - @GET - @Produces("application/json") - @Path("/whoami") - public Response show(@Context HttpServletRequest request, @Context HttpServletResponse response) { - Principal principal = request.getUserPrincipal(); - Map output = new HashMap<>(); - if (principal != null) { - output.put("name", principal.getName()); - if (principal instanceof WindowsPrincipal) { - WindowsPrincipal windowsPrincipal = (WindowsPrincipal) principal; - List> gropus = new ArrayList<>(); - for (waffle.windows.auth.WindowsAccount account : windowsPrincipal.getGroups().values()) { - Map m = new HashMap<>(); - m.put("name", account.getName()); - m.put("domain", account.getDomain()); - m.put("fqn", account.getFqn()); - m.put("sid", account.getSidString()); - gropus.add(m); - } - output.put("groups", gropus); - } - } else { - HttpSession session = request.getSession(false); - if (session != null) { - User user = (User) session.getAttribute(Constants.SESSION_USER); - if (user != null) { - AccessToken token = user.getAccessToken(user.getPrimaryLogin()); - output.put("name", token.getId()); - output.put("warning", "null principal - grab from user"); - } - } - if (output.isEmpty()) { - output.put(Constants.ERROR_MESSAGE, "null principal"); - } - } - return WebUtility.getResponse(output, 200); - } - -} +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * 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. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *******************************************************************************/ +package prerna.semoss.web.services.local; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Base64; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.UUID; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import javax.annotation.security.PermitAll; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.NewCookie; +import javax.ws.rs.core.Response; + +import org.apache.http.client.ClientProtocolException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.javatuples.Pair; +import org.json.JSONArray; +import org.owasp.encoder.Encode; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.base.Strings; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import prerna.auth.AccessToken; +import prerna.auth.AuthProvider; +import prerna.auth.SyncUserAssetsThread; +import prerna.auth.User; +import prerna.auth.external.ExternalAuthorizationHelper; +import prerna.auth.utils.AbstractSecurityUtils; +import prerna.auth.utils.SecurityAPIUserUtils; +import prerna.auth.utils.SecurityAdminUtils; +import prerna.auth.utils.SecurityExternalConnectorsUtils; +import prerna.auth.utils.SecurityNativeUserUtils; +import prerna.auth.utils.SecurityUpdateUtils; +import prerna.auth.utils.SecurityUserUtils; +import prerna.cluster.util.ClusterUtil; +import prerna.io.connector.GenericTokenFiller; +import prerna.io.connector.github.GithubTokenFiller; +import prerna.io.connector.google.GoogleTokenFiller; +import prerna.io.connector.jira.JiraTokenFiller; +import prerna.io.connector.ms.MicrosoftTokenFiller; +import prerna.io.connector.okta.OktaTokenFiller; +import prerna.io.connector.salesforce.SalesforceTokenFiller; +import prerna.io.connector.servicenow.ServiceNowTokenFiller; +import prerna.io.connector.surveymonkey.MonkeyProfile; +import prerna.sablecc2.om.execptions.SemossPixelException; +import prerna.security.HttpHelperUtility; +import prerna.usertracking.UserTrackingUtils; +import prerna.util.BeanFiller; +import prerna.util.Constants; +import prerna.util.SocialPropertiesUtil; +import prerna.util.Utility; +import prerna.util.git.GitRepoUtils; +import prerna.util.ldap.ILdapAuthenticator; +import prerna.util.ldap.LDAPPasswordChangeRequiredException; +import prerna.util.linotp.LinOTPResponse; +import prerna.util.linotp.LinOTPUtil; +import prerna.web.conf.DBLoader; +import prerna.web.conf.UserSessionLoader; +import prerna.web.services.util.WebUtility; +import waffle.servlet.WindowsPrincipal; + +@Path("/auth") +@PermitAll +public class UserResource { + + private static final Logger classLogger = LogManager.getLogger(UserResource.class); + + private static final String CUSTOM_REDIRECT_SESSION_KEY = "custom_redirect"; + + private static SocialPropertiesUtil socialData = null; + static { + socialData = SocialPropertiesUtil.getInstance(); + } + + private static final Charset UTF8 = Charset.forName("UTF-8"); + + /** + * Returns the active login providers for the current session user. + * + * @param request inbound HTTP request + * @return provider-name map response + */ + @GET + @Path("/logins") + public Response getAllLogins(@Context HttpServletRequest request) { + List newCookies = new ArrayList<>(); + HttpSession session = request.getSession(false); + User semossUser = null; + if (session != null) { + semossUser = (User) session.getAttribute(Constants.SESSION_USER); + } + + if (semossUser == null) { + // not authenticated + // remove any cookies we shouldn't have + WebUtility.expireSessionCookies(request, newCookies); + + if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { + session.invalidate(); + } + } + + Map retMap = User.getLoginNames(semossUser); + return WebUtility.getResponse(retMap, 200, newCookies.toArray(new NewCookie[] {})); + } + /** + * Returns the active connection providers for the current session user. + * + * @param request inbound HTTP request + * @return provider-name map response + */ + @GET + @Path("/connections") + public Response getAllConnections(@Context HttpServletRequest request) { + List newCookies = new ArrayList<>(); + HttpSession session = request.getSession(false); + User semossUser = null; + if (session != null) { + semossUser = (User) session.getAttribute(Constants.SESSION_USER); + } + + if (semossUser == null) { + // not authenticated + // remove any cookies we shouldn't have + WebUtility.expireSessionCookies(request, newCookies); + + if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { + session.invalidate(); + } + } + Map retMap = User.getConnectionsNames(semossUser); + return WebUtility.getResponse(retMap, 200, newCookies.toArray(new NewCookie[] {})); + } + + /** + * Logs a user out of one provider or all providers in the current session. + * + * @param provider provider name or {@code ALL} + * @param disableRedirect when true, do not send a redirect response + * @param request inbound HTTP request + * @param response outbound HTTP response + * @return logout result payload + * @throws IOException when redirect writing fails + */ + @GET + @Produces("application/json") + @Path("/logout/{provider}") + public Response logout(@PathParam("provider") String provider, + @QueryParam("disableRedirect") boolean disableRedirect, @Context HttpServletRequest request, + @Context HttpServletResponse response) throws IOException { + boolean noUser = false; + boolean removed = false; + + provider = WebUtility.inputSanitizer(provider); + + HttpSession session = request.getSession(); + User thisUser = (User) session.getAttribute(Constants.SESSION_USER); + if (thisUser == null) { + Map ret = new HashMap<>(); + ret.put("success", false); + ret.put(Constants.ERROR_MESSAGE, "No user is currently logged in the session"); + return WebUtility.getResponse(ret, 400); + } + + // log the user logout + classLogger.info("User is logging out of provider {}", provider); + provider = WebUtility.inputSanitizer(provider); + if (provider.equalsIgnoreCase("ALL")) { + removed = true; + noUser = true; + } else { + AuthProvider token = AuthProvider.valueOf(provider.toUpperCase()); + boolean loginToken = thisUser.getAccessToken(token) != null; + boolean resourceToken = thisUser.getResourceAccessToken(token) != null; + + if (resourceToken) { + thisUser.dropResourceAccessToken(token); + removed = true; + if (!loginToken) { + session.setAttribute(Constants.SESSION_USER, thisUser); + } + } + if (loginToken) { + String assetEngineId = null; + + // TODO: what does this part do? + // TODO: feel like when logout need to adjust the asset id + if (thisUser.getLogins().size() == 1) { + thisUser.getAssetProjectId(token); + } + removed = thisUser.dropAccessToken(token) || removed; + if (thisUser.getLogins().isEmpty()) { + noUser = true; + } else { + session.setAttribute(Constants.SESSION_USER, thisUser); + Thread.ofVirtual().start(new SyncUserAssetsThread(assetEngineId)); + // put the new map for the user space + session.setAttribute(Constants.USER_ASSET_IDS, thisUser.getAssetEngineMap()); + } + } + } + + List nullCookies = null; + if (noUser) { + // when we call session.invalidate() the UserSessionLoader will properly log is + // user logout or tomcat ending + session.setAttribute(UserSessionLoader.IS_USER_LOGOUT, true); + classLogger.info("User has logged out from all providers in the session"); + // well, you have logged out and we always require a login + // so i will redirect you by default unless you specifically say not to + if (!disableRedirect) { + response.setStatus(302); + + String customUrl = DBLoader.getCustomLogoutUrl(); + if (customUrl != null && !customUrl.isEmpty()) { + response.setHeader("redirect", customUrl); + response.sendError(302, "Need to redirect to " + customUrl); + } else { + String redirectUrl = WebUtility.inputSanitizer(request.getHeader("referer")); + if (DBLoader.useLogoutPage()) { + String scheme = WebUtility.inputSanitizer(request.getScheme()); + if (!scheme.trim().equalsIgnoreCase("https") && !scheme.trim().equalsIgnoreCase("http")) { + throw new IllegalArgumentException("scheme is invalid, please input proper scheme"); + } + String serverName = WebUtility.inputSanitizer(request.getServerName()); // hostname.com + int serverPort = request.getServerPort(); // 8080 + String contextPath = WebUtility.inputSanitizer(request.getContextPath()); // /Monolith + + redirectUrl = ""; + redirectUrl += scheme + "://" + serverName; + if (serverPort != 80 && serverPort != 443) { + redirectUrl += ":" + serverPort; + } + redirectUrl += contextPath + "/logout/"; + response.setHeader("redirect", redirectUrl); + response.sendError(302, "Need to redirect to " + redirectUrl); + } else { + redirectUrl = redirectUrl + WebUtility.determineLoginExtension(request); + String encodedRedirectUrl = Encode.forHtml(redirectUrl); + response.setHeader("redirect", encodedRedirectUrl); + response.sendError(302, "Need to redirect to " + encodedRedirectUrl); + } + } + } + + // remove the cookie from the browser + // for the session id + classLogger.info("Removing session token"); + nullCookies = new ArrayList<>(); + WebUtility.expireSessionCookies(request, nullCookies); + // invalidate the session + session.invalidate(); + } + + Map ret = new HashMap<>(); + ret.put("success", removed); + if (nullCookies == null) { + return WebUtility.getResponse(ret, 200); + } + + return WebUtility.getResponseNoCache(ret, 200, nullCookies.toArray(new NewCookie[] {})); + } + /** + * Adds or updates a resource access token in the current user session. + * + * @param token normalized access token + * @param request inbound HTTP request + */ + public static void addResourceAccessToken(AccessToken token, HttpServletRequest request) { + HttpSession session = request.getSession(); + User semossUser = (User) session.getAttribute(Constants.SESSION_USER); + if (semossUser == null) { + classLogger.error("No user found in session when trying to add resource access token"); + return; + } + + // add new resource access token to the user + semossUser.setResourceAccessToken(token); + semossUser.setAnonymous(false); + session.setAttribute(Constants.SESSION_USER, semossUser); + + // log the user resource connection + classLogger.info("User is connected to provider " + token.getProvider()); + } + + /** + * Adds or updates an authenticated access token in the current user session. + * + * @param token normalized access token + * @param request inbound HTTP request + * @param autoAdd when true, create/update the user record automatically + */ + public static void addAccessToken(AccessToken token, HttpServletRequest request, boolean autoAdd) { + HttpSession session = request.getSession(); + User semossUser = (User) session.getAttribute(Constants.SESSION_USER); + // all of this is now in the user + boolean firstLogin = semossUser == null; + if (firstLogin) { + semossUser = new User(); + session.setAttribute(Constants.SESSION_USER_ID_LOG, token.getId()); + } + // add new users into the database + if (autoAdd) { + SecurityUpdateUtils.addOAuthUser(token); + } + // validate the user's login + // that they are not locked + // and to update the last login date + try { + SecurityUpdateUtils.validateUserLogin(token); + } catch (Exception e) { + classLogger.error("Unexpected error in addAccessToken", e); + } + semossUser.setAccessToken(token); + semossUser.setAnonymous(false); + + // also set the user metadata + SecurityUserUtils.loadUserMetadata(token); + + session.setAttribute(Constants.SESSION_USER, semossUser); + WebUtility.loggingContextLoginEvent(session); + + UserResource.userTrackingLogin(request, semossUser, token.getProvider()); + + // log the user login + classLogger.info("User is logging in with provider {}", token.getProvider()); + + // only for first login + // lets see if there is an external auth + // that we should be loading + if (firstLogin && Boolean + .parseBoolean(Utility.getDIHelperProperty(Constants.EXTERNAL_PERMISSION_MANAGEMENT_ENABLED) + "")) { + try { + ExternalAuthorizationHelper.updateEnginePermissionsBasedOnApiCall(semossUser); + } catch (Exception e) { + classLogger.error("Unexpected error in addAccessToken", e); + } + } + } + + /** + * Records a user login event in the tracking system. + * + * @param request inbound HTTP request + * @param semossUser authenticated user + * @param ap authentication provider used for login + */ + public static void userTrackingLogin(HttpServletRequest request, User semossUser, AuthProvider ap) { + String ip = WebUtility.getClientIp(request); + if (request.getSession() != null && request.getSession().getId() != null) { + UserTrackingUtils.registerLogin(request.getSession().getId(), ip, semossUser, ap); + } else { + UserTrackingUtils.registerLogin("NO_SESSION_ID", ip, semossUser, ap); + } + } + + ////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// + + /** + * User info method calls + */ + + /** + * Gets user profile information for ADFS. + */ + @GET + @Produces("application/json") + @Path("/userinfo/adfs") + public Response userinfoADFS(@Context HttpServletRequest request) { + Map ret = new HashMap<>(); + HttpSession session = request.getSession(false); + User semossUser = null; + if (session != null) { + semossUser = (User) session.getAttribute(Constants.SESSION_USER); + } + + if (semossUser == null) { + List newCookies = new ArrayList<>(); + // not authenticated + // remove any cookies we shouldn't have + WebUtility.expireSessionCookies(request, newCookies); + + if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { + session.invalidate(); + } + + ret.put(Constants.ERROR_MESSAGE, "Log into your ADFS account"); + return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); + } + + String prefix = "adfs_"; + String beanProps = socialData.getProperty(prefix + "beanProps"); + String jsonPattern = socialData.getProperty(prefix + "jsonPattern"); + + String[] beanPropsArr = beanProps.split(",", -1); + + String accessString = null; + try { + AccessToken adfsToken = semossUser.getAccessToken(AuthProvider.ADFS); + accessString = adfsToken.getAccess_token(); + String json = decodeTokenPayload(adfsToken.getAccess_token()); + adfsToken = (AccessToken) BeanFiller.fillFromJson(json, jsonPattern, beanPropsArr, adfsToken); + String name = adfsToken.getName(); + ret.put("name", name); + + return WebUtility.getResponse(ret, 200); + } catch (Exception e) { + ret.put(Constants.ERROR_MESSAGE, "Log into your ADFS account"); + return WebUtility.getResponse(ret, 200); + } + } + + /** + * Gets user profile information for Dropbox. + */ + @GET + @Produces("application/json") + @Path("/userinfo/dropbox") + public Response userinfoDropbox(@Context HttpServletRequest request) { + Map ret = new HashMap<>(); + HttpSession session = request.getSession(false); + User semossUser = null; + if (session != null) { + semossUser = (User) session.getAttribute(Constants.SESSION_USER); + } + + if (semossUser == null) { + List newCookies = new ArrayList<>(); + // not authenticated + // remove any cookies we shouldn't have + WebUtility.expireSessionCookies(request, newCookies); + + if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { + session.invalidate(); + } + + ret.put(Constants.ERROR_MESSAGE, "Log into your DropBox account"); + return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); + } + + String[] beanProps = { "name", "profile" }; // add is done when you have a list + String jsonPattern = "[name.display_name, profile_photo_url]"; + String accessString = null; + try { + AccessToken dropToken = semossUser.getAccessToken(AuthProvider.DROPBOX); + accessString = dropToken.getAccess_token(); + } catch (Exception e) { + ret.put(Constants.ERROR_MESSAGE, "Log into your DropBox account"); + return WebUtility.getResponse(ret, 200); + } + String url = "https://api.dropboxapi.com/2/users/get_current_account"; + + String output = HttpHelperUtility.makePostCall(url, accessString, null, true); + AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, + new AccessToken()); + try { + if (accessToken2.getProfile() == null || accessToken2.getProfile().equalsIgnoreCase("null")) { + ret.put("picture", ""); + } else { + ret.put("picture", accessToken2.getProfile()); + } + ret.put("name", accessToken2.getName()); + } catch (Exception e) { + classLogger.error("Unexpected error in userinfoDropbox", e); + } + return WebUtility.getResponse(ret, 200); + + } + + /** + * Gets user profile information for GitHub. + */ + @GET + @Produces("application/json") + @Path("/userinfo/github") + public Response userinfoGithub(@Context HttpServletRequest request) { + Map ret = new HashMap<>(); + HttpSession session = request.getSession(false); + User semossUser = null; + if (session != null) { + semossUser = (User) session.getAttribute(Constants.SESSION_USER); + } + + if (semossUser == null) { + List newCookies = new ArrayList<>(); + // not authenticated + // remove any cookies we shouldn't have + WebUtility.expireSessionCookies(request, newCookies); + + if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { + session.invalidate(); + } + + ret.put(Constants.ERROR_MESSAGE, "Log into your Github account"); + return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); + } + + String[] beanProps = { "name", "profile" }; // add is done when you have a list + String jsonPattern = "[name,login]"; + + String accessString = null; + try { + AccessToken gitToken = semossUser.getAccessToken(AuthProvider.GITHUB); + accessString = gitToken.getAccess_token(); + } catch (Exception e) { + ret.put(Constants.ERROR_MESSAGE, "Log into your Github account"); + return WebUtility.getResponse(ret, 200); + } + + String url = "https://api.github.com/user"; + + String output = HttpHelperUtility.makeGetCall(url, accessString, null, true); + AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, + new AccessToken()); + try { + ret.put("name", accessToken2.getProfile()); + } catch (Exception e) { + classLogger.error("Unexpected error in userinfoGithub", e); + } + return WebUtility.getResponse(ret, 200); + } + + /** + * Gets user profile information for Google. + */ + @GET + @Produces("application/json") + @Path("/userinfo/google") + public Response userinfoGoogle(@Context HttpServletRequest request) { + Map ret = new HashMap<>(); + HttpSession session = request.getSession(false); + User semossUser = null; + if (session != null) { + semossUser = (User) session.getAttribute(Constants.SESSION_USER); + } + + if (semossUser == null) { + List newCookies = new ArrayList<>(); + // not authenticated + // remove any cookies we shouldn't have + WebUtility.expireSessionCookies(request, newCookies); + + if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { + session.invalidate(); + } + + ret.put(Constants.ERROR_MESSAGE, "Log into your Google account"); + return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); + } + + String[] beanProps = { "name", "profile" }; + String jsonPattern = "[name, picture]"; + String accessString = null; + try { + AccessToken googleToken = semossUser.getAccessToken(AuthProvider.GOOGLE); + accessString = googleToken.getAccess_token(); + } catch (Exception e) { + ret.put(Constants.ERROR_MESSAGE, "Log into your Google account"); + return WebUtility.getResponse(ret, 200); + } + + String url = "https://www.googleapis.com/oauth2/v3/userinfo"; + Map params = new HashMap<>(); + params.put("access_token", accessString); + params.put("alt", "json"); + + String output = HttpHelperUtility.makeGetCall(url, accessString, params, true); + AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, + new AccessToken()); + try { + ret.put("name", accessToken2.getName()); + if (accessToken2.getProfile() != null) { + ret.put("picture", accessToken2.getProfile()); + } + } catch (Exception e) { + classLogger.error("Unexpected error in userinfoGoogle", e); + } + + return WebUtility.getResponse(ret, 200); + } + + /** + * Gets user profile information for Jira. + */ + @GET + @Produces("application/json") + @Path("/userinfo/jira") + public Response userinfoJira(@Context HttpServletRequest request) { + Map ret = new HashMap<>(); + HttpSession session = request.getSession(false); + User semossUser = null; + if (session != null) { + semossUser = (User) session.getAttribute(Constants.SESSION_USER); + } + if (semossUser == null) { + List newCookies = new ArrayList<>(); + // not authenticated + // remove any cookies we shouldn't have + WebUtility.expireSessionCookies(request, newCookies); + if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { + session.invalidate(); + } + ret.put(Constants.ERROR_MESSAGE, "Log into your Jira account"); + return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); + } + String[] beanProps = { "name" }; + String jsonPattern = "[name]"; + String accessString = null; + try { + AccessToken jiraToken = semossUser.getAccessToken(AuthProvider.JIRA); + accessString = jiraToken.getAccess_token(); + String url = "https://api.atlassian.com/me"; + Map params = new HashMap<>(); + params.put("access_token", accessString); + params.put("alt", "json"); + String output = HttpHelperUtility.makeGetCall(url, accessString, params, true); + AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, + new AccessToken()); + String name = accessToken2.getName(); + ret.put("name", name); + return WebUtility.getResponse(ret, 200); + } catch (Exception e) { + classLogger.error("Failed to fetch Jira user info", e); + ret.put(Constants.ERROR_MESSAGE, "Log into your Jira account"); + return WebUtility.getResponse(ret, 401); + } + } + + /** + * Backwards-compatible alias for the Microsoft user-info endpoint. + */ + @GET + @Produces("application/json") + @Path("/userinfo/ms") + @Deprecated + public Response userinfoMs(@Context HttpServletRequest request) { + return userinfoMicrosoft(request); + } + + /** + * Gets user profile information for Microsoft. + * + * @param request inbound HTTP request + * @return user info response for Microsoft + */ + @GET + @Produces("application/json") + @Path("/userinfo/microsoft") + public Response userinfoMicrosoft(@Context HttpServletRequest request) { + Map ret = new HashMap<>(); + HttpSession session = request.getSession(false); + User semossUser = null; + if (session != null) { + semossUser = (User) session.getAttribute(Constants.SESSION_USER); + } + + if (semossUser == null) { + List newCookies = new ArrayList<>(); + // not authenticated + // remove any cookies we shouldn't have + WebUtility.expireSessionCookies(request, newCookies); + + if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { + session.invalidate(); + } + + ret.put(Constants.ERROR_MESSAGE, "Log into your Microsoft account"); + return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); + } + + String[] beanProps = { "name" }; + String jsonPattern = "[displayName]"; + + String accessString = null; + try { + AccessToken msToken = semossUser.getAccessToken(AuthProvider.MICROSOFT); + accessString = msToken.getAccess_token(); + String url = "https://graph.microsoft.com/v1.0/me/"; + String output = HttpHelperUtility.makeGetCall(url, accessString, null, true); + AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, + new AccessToken()); + String name = accessToken2.getName(); + ret.put("name", name); + return WebUtility.getResponse(ret, 200); + + } catch (Exception e) { + ret.put(Constants.ERROR_MESSAGE, "Log into your Microsoft account"); + return WebUtility.getResponse(ret, 200); + } + } + + /** + * Gets user profile information for Okta. + * + * @param request inbound HTTP request + * @return user info response for Okta + */ + @GET + @Produces("application/json") + @Path("/userinfo/okta") + public Response userinfoOkta(@Context HttpServletRequest request) { + String prefix = "okta_"; + + Map ret = new HashMap<>(); + HttpSession session = request.getSession(false); + User semossUser = null; + if (session != null) { + semossUser = (User) session.getAttribute(Constants.SESSION_USER); + } + + if (semossUser == null) { + List newCookies = new ArrayList<>(); + // not authenticated + // remove any cookies we shouldn't have + WebUtility.expireSessionCookies(request, newCookies); + + if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { + session.invalidate(); + } + + ret.put(Constants.ERROR_MESSAGE, "Log into your Okta account"); + return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); + } + + String[] beanPropsArr = { "id", "name", "email", "phone" }; + String jsonPattern = "[sub,name,email,phone_number]"; + + String accessString = null; + try { + AccessToken accessToken = semossUser.getAccessToken(AuthProvider.OKTA); + accessString = accessToken.getAccess_token(); + String userInfoURL = socialData.getProperty(prefix + "userinfo_url"); + String socialBeanProps = socialData.getProperty(prefix + "beanProps"); + + if (socialBeanProps != null && !socialBeanProps.trim().isEmpty()) { + beanPropsArr = socialBeanProps.split(",", -1); + } + + String socialJsonPattern = socialData.getProperty(prefix + "jsonPattern"); + + if (socialJsonPattern != null && !socialJsonPattern.trim().isEmpty()) { + jsonPattern = socialJsonPattern; + } + + String output = HttpHelperUtility.makeGetCall(userInfoURL, accessString, null, true); + AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanPropsArr, + new AccessToken()); + String name = accessToken2.getName(); + ret.put("name", name); + return WebUtility.getResponse(ret, 200); + } catch (Exception e) { + ret.put(Constants.ERROR_MESSAGE, "Log into your Okta account"); + return WebUtility.getResponse(ret, 200); + } + } + + /** + * Gets user profile information for Salesforce. + */ + @GET + @Produces("application/json") + @Path("/userinfo/salesforce") + public Response userinfoSalesforce(@Context HttpServletRequest request) { + Map ret = new HashMap<>(); + HttpSession session = request.getSession(false); + User semossUser = null; + if (session != null) { + semossUser = (User) session.getAttribute(Constants.SESSION_USER); + } + + if (semossUser == null) { + List newCookies = new ArrayList<>(); + // not authenticated + // remove any cookies we shouldn't have + WebUtility.expireSessionCookies(request, newCookies); + + if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { + session.invalidate(); + } + + ret.put(Constants.ERROR_MESSAGE, "Log into your Salesforce account"); + return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); + } + + String[] beanProps = { "name" }; + String jsonPattern = "[name]"; + + String accessString = null; + try { + AccessToken salesforceToken = semossUser.getAccessToken(AuthProvider.SALESFORCE); + accessString = salesforceToken.getAccess_token(); + String url = "https://login.salesforce.com/services/oauth2/userinfo"; + Map params = new HashMap<>(); + params.put("access_token", accessString); + params.put("alt", "json"); + + String output = HttpHelperUtility.makeGetCall(url, accessString, params, true); + AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, + new AccessToken()); + String name = accessToken2.getName(); + ret.put("name", name); + return WebUtility.getResponse(ret, 200); + + } catch (Exception e) { + classLogger.error("Failed to fetch Salesforce user info", e); + ret.put(Constants.ERROR_MESSAGE, "Log into your Salesforce account"); + return WebUtility.getResponse(ret, 401); + } + + } + + /** + * Gets user profile information for ServiceNow. + */ + @GET + @Produces("application/json") + @Path("/userinfo/servicenow") + public Response userinfoServiceNow(@Context HttpServletRequest request) { + Map ret = new HashMap<>(); + HttpSession session = request.getSession(false); + User semossUser = null; + if (session != null) { + semossUser = (User) session.getAttribute(Constants.SESSION_USER); + } + + if (semossUser == null) { + List newCookies = new ArrayList<>(); + // not authenticated + // remove any cookies we shouldn't have + WebUtility.expireSessionCookies(request, newCookies); + + if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { + session.invalidate(); + } + + ret.put(Constants.ERROR_MESSAGE, "Log into your ServiceNow account"); + return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); + } + + String[] beanProps = { "name" }; + String jsonPattern = "[result.name]"; + + String accessString = null; + try { + AccessToken servicenowToken = semossUser.getAccessToken(AuthProvider.SERVICENOW); + accessString = servicenowToken.getAccess_token(); + String prefix = "servicenow_"; + String userinfoUrl = socialData.getProperty(prefix + "userinfo_url"); + Map params = new HashMap<>(); + params.put("access_token", accessString); + params.put("alt", "json"); + + String output = HttpHelperUtility.makeGetCall(userinfoUrl, accessString, params, true); + AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanProps, + new AccessToken()); + String name = accessToken2.getName(); + ret.put("name", name); + return WebUtility.getResponse(ret, 200); + + } catch (Exception e) { + classLogger.error("Failed to fetch ServiceNow user info", e); + ret.put(Constants.ERROR_MESSAGE, "Log into your ServiceNow account"); + return WebUtility.getResponse(ret, 401); + } + + } + + /** + * Gets user profile information for a generic OAuth provider. + */ + @GET + @Produces("application/json") + @Path("/userinfo/{provider}") + public Response userinfoGeneric(@PathParam("provider") String provider, @Context HttpServletRequest request) { + provider = WebUtility.inputSanitizer(provider); + + AuthProvider providerEnum = AuthProvider.getProviderFromString(provider.toUpperCase()); + Map ret = new HashMap<>(); + HttpSession session = request.getSession(false); + + User semossUser = null; + if (session != null) { + semossUser = (User) session.getAttribute(Constants.SESSION_USER); + } + + if (semossUser == null) { + List newCookies = new ArrayList<>(); + // not authenticated + // remove any cookies we shouldn't have + WebUtility.expireSessionCookies(request, newCookies); + + if (session != null && (session.isNew() || request.isRequestedSessionIdValid())) { + session.invalidate(); + } + + ret.put(Constants.ERROR_MESSAGE, "Log into your " + providerEnum.name() + " account"); + return WebUtility.getResponseNoCache(ret, 200, newCookies.toArray(new NewCookie[] {})); + } + + String prefix = provider + "_"; + String userInfoURL = socialData.getProperty(prefix + "userinfo_url"); + // "name","id","email" + String beanProps = socialData.getProperty(prefix + "beanProps"); + String jsonPattern = socialData.getProperty(prefix + "jsonPattern"); + + String[] beanPropsArr = beanProps.split(",", -1); + + String accessString = null; + try { + AccessToken genericToken = semossUser.getAccessToken(providerEnum); + accessString = genericToken.getAccess_token(); + // String url = "https://graph.microsoft.com/v1.0/me/"; + String output = HttpHelperUtility.makeGetCall(userInfoURL, accessString, null, true); + AccessToken accessToken2 = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanPropsArr, + new AccessToken()); + String name = accessToken2.getName(); + ret.put("name", name); + + return WebUtility.getResponse(ret, 200); + } catch (Exception e) { + ret.put(Constants.ERROR_MESSAGE, "Log into your " + providerEnum.toString() + " account"); + return WebUtility.getResponse(ret, 200); + } + } + + ////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// + + /** + * Initializes an OAuth login flow session and stores a custom redirect value + * when present. + * + * @param request inbound HTTP request + * @return existing or newly-created session + */ + private HttpSession initializeOAuthLoginSession(HttpServletRequest request) { + HttpSession session = request.getSession(false); + String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); + if (customRedirect != null && !customRedirect.isEmpty()) { + if (session == null) { + session = request.getSession(); + } + session.setAttribute(CUSTOM_REDIRECT_SESSION_KEY, customRedirect); + } + return session; + } + + /** + * Resolves the authenticated user from a session. + * + * @param session HTTP session + * @return session user or {@code null} + */ + private User getSessionUser(HttpSession session) { + if (session == null) { + return null; + } + return (User) session.getAttribute(Constants.SESSION_USER); + } + + /** + * Reloads the session user after an OAuth callback updates session state. + * + * @param request inbound HTTP request + * @param session current session reference + * @return session user or {@code null} + */ + private User refreshSessionUser(HttpServletRequest request, HttpSession session) { + if (session != null || (session = request.getSession(false)) != null) { + return (User) session.getAttribute(Constants.SESSION_USER); + } + return null; + } + + /** + * Checks whether a user has a resource access token for the requested provider. + * + * @param user user to inspect + * @param provider authentication provider + * @return {@code true} when a token exists + */ + private boolean hasResourceAccessToken(User user, AuthProvider provider) { + return user != null && user.getResourceAccessToken(provider) != null; + } + + /** + * Checks whether a user has an access token for the requested provider. + * + * @param user user to inspect + * @param provider authentication provider + * @return {@code true} when a token exists + */ + private boolean hasAccessToken(User user, AuthProvider provider) { + return user != null && user.getAccessToken(provider) != null; + } + + /** + * Checks whether the current session already has an authenticated login user. + * + * @param user session user to inspect + * @return {@code true} when the session user exists and has at least one login + */ + private boolean hasLoggedInUser(User user) { + return user != null && user.getLogins() != null && !user.getLogins().isEmpty(); + } + + /** + * Encodes the request query string for safe OAuth parsing. + * + * @param request inbound HTTP request + * @return encoded query string + */ + private String getEncodedQueryString(HttpServletRequest request) { + return WebUtility.encodeHTTPUri(request.getQueryString()); + } + + /** + * Checks whether the callback query contains an OAuth authorization code. + * + * @param queryString encoded callback query string + * @return {@code true} when a code parameter is present + */ + private boolean hasOAuthCode(String queryString) { + return queryString != null && queryString.contains("code"); + } + + /** + * Handles ADFS OAuth login callback flow. + */ + @GET + @Produces("application/json") + @Path("/login/adfs") + public Response loginADFS(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + if (socialData.getLoginsAllowed().get("adfs") == null || !socialData.getLoginsAllowed().get("adfs")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "ADFS login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.ADFS)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String prefix = "adfs_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String scope = socialData.getProperty(prefix + "scope"); + String token_url = socialData.getProperty(prefix + "token_url"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("scope", scope); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("grant_type", "authorization_code"); + params.put("client_secret", clientSecret); + + if (Strings.isNullOrEmpty(token_url)) { + throw new IllegalArgumentException("Token URL can not be null or empty"); + } + + AccessToken accessToken = HttpHelperUtility.getIdToken(token_url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getADFSRedirect(request)); + return null; + } + String json = decodeTokenPayload(accessToken.getAccess_token()); + + accessToken.setProvider(AuthProvider.ADFS); + String beanProps = socialData.getProperty(prefix + "beanProps"); + String jsonPattern = socialData.getProperty(prefix + "jsonPattern"); + String[] beanPropsArr = beanProps.split(",", -1); + accessToken = (AccessToken) BeanFiller.fillFromJson(json, jsonPattern, beanPropsArr, accessToken); + + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.ADFS)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getADFSRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Decodes the JWT payload segment from a token value. + * + * @param token JWT access token + * @return decoded JSON payload + */ + private String decodeTokenPayload(String token) { + String[] parts = token.split("\\.", 0); + byte[] bytes = Base64.getUrlDecoder().decode(parts[1]); + String payload = new String(bytes, StandardCharsets.UTF_8); + return payload; + } + + /** + * Builds the ADFS authorization redirect URL. + * + * @param request inbound HTTP request + * @return ADFS authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getADFSRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "adfs_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String scope = socialData.getProperty(prefix + "scope"); // need to set this up and reuse + String auth_url = socialData.getProperty(prefix + "auth_url"); + + String state = UUID.randomUUID().toString(); + + if (Strings.isNullOrEmpty(auth_url)) { + throw new IllegalArgumentException("A URL can not be null or empty"); + } + String redirectUrl = auth_url + "?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" + + URLEncoder.encode(redirectUri, UTF8) + "&response_mode=query" + "&scope=" + + URLEncoder.encode(scope, UTF8) + "&state=" + state; + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles Dropbox OAuth login callback flow. + */ + @GET + @Produces("application/json") + @Path("/login/dropbox") + public Response loginDropBox(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + if (socialData.getLoginsAllowed().get("dropbox") == null || !socialData.getLoginsAllowed().get("dropbox")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Dropbox login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.DROPBOX)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String prefix = "dropbox_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("grant_type", "authorization_code"); + params.put("client_secret", clientSecret); + + String url = "https://www.dropbox.com/oauth2/token"; + + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getDBRedirect(request)); + return null; + } + accessToken.setProvider(AuthProvider.DROPBOX); + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.DROPBOX)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getDBRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the Dropbox authorization redirect URL. + * + * @param request inbound HTTP request + * @return Dropbox authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getDBRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "dropbox_"; + + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String role = socialData.getProperty(prefix + "role"); // need to set this up and reuse + String redirectUrl = "https://www.dropbox.com/oauth2/authorize?" + "client_id=" + clientId + + "&response_type=code" + "&redirect_uri=" + URLEncoder.encode(redirectUri, UTF8) + "&require_role=" + + role + "&disable_signup=false"; + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles GitHub OAuth login callback flow. + * https://developer.github.com/apps/building-oauth-apps/authorization-options-for-oauth-apps/ + */ + @GET + @Produces("application/json") + @Path("/login/github") + public Response loginGithub(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + if (socialData.getLoginsAllowed().get("github") == null || !socialData.getLoginsAllowed().get("github")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "GitHub login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.GITHUB)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code and state should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.5 + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + String state = URLDecoder.decode(outputs[1], StandardCharsets.UTF_8); + if (code.matches("[ -~]+") && state.matches("[ -~]+")) { + String prefix = "github_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("state", state); + params.put("client_secret", clientSecret); + + String url = "https://github.com/login/oauth/access_token"; + + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, false, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getGithubRedirect(request)); + return null; + } + accessToken.setProvider(AuthProvider.GITHUB); + + try { + GitRepoUtils.addCertForDomain(url); + } catch (Exception e) { + classLogger.error("Unexpected error in loginGithub", e); + } + // add specific Git values + GithubTokenFiller profiler = new GithubTokenFiller(); + profiler.fillAccessToken(accessToken, null, null, null, null); + + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.GITHUB)) { + // not authenticated + try { + GitRepoUtils.addCertForDomain("https://github.com"); + } catch (Exception e) { + classLogger.error("Unexpected error in loginGithub", e); + } + response.setStatus(302); + response.sendRedirect(getGithubRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the GitHub authorization redirect URL. + * + * @param request inbound HTTP request + * @return GitHub authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getGithubRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "github_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String scope = socialData.getProperty(prefix + "scope"); + + String redirectUrl = "https://github.com/login/oauth/authorize?" + "client_id=" + clientId + "&redirect_uri=" + + redirectUri + "&state=" + UUID.randomUUID().toString() + "&allow_signup=true" + "&scope=" + + URLEncoder.encode(scope, UTF8); + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles GitLab OAuth login callback flow. + * https://docs.gitlab.com/13.12/ee/integration/oauth_provider.html + * https://docs.gitlab.com/13.12/ee/api/oauth2.html + */ + @GET + @Produces("application/json") + @Path("/login/gitlab") + public Response loginGitlab(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + if (socialData.getLoginsAllowed().get("gitlab") == null || !socialData.getLoginsAllowed().get("gitlab")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "GitLab login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + String prefix = "gitlab_"; + + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.GITLAB)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code and state should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.5 + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + String state = URLDecoder.decode(outputs[1], StandardCharsets.UTF_8); + if (code.matches("[ -~]+") && state.matches("[ -~]+")) { + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String token_url = socialData.getProperty(prefix + "token_url"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("state", state); + params.put("client_secret", clientSecret); + params.put("grant_type", "authorization_code"); + + AccessToken accessToken = HttpHelperUtility.getAccessToken(token_url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getGitlabRedirect(request)); + return null; + } + accessToken.setProvider(AuthProvider.GITLAB); + + String beanProps = socialData.getProperty(prefix + "beanProps"); + String jsonPattern = socialData.getProperty(prefix + "jsonPattern"); + String userinfo_url = socialData.getProperty(prefix + "userinfo_url"); + String[] beanPropsArr = beanProps.split(",", -1); + + String output = HttpHelperUtility.makeGetCall(userinfo_url, accessToken.getAccess_token(), null, + true); + accessToken = (AccessToken) BeanFiller.fillFromJson(output, jsonPattern, beanPropsArr, accessToken); + + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.GITLAB)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getGitlabRedirect(request)); + return null; + } + + if (Boolean.parseBoolean(socialData.getProperty(prefix + "groups"))) { + // get groups + String group_url = socialData.getProperty(prefix + "group_url"); + String groupsJson = HttpHelperUtility.makeGetCall(group_url, + userObj.getAccessToken(AuthProvider.GITLAB).getAccess_token()); + String groupJsonPattern = socialData.getProperty(prefix + "groupJsonPattern"); + // String beanProps = socialData.getProperty(prefix + "groupBeanProps"); + // String[] beanPropsArr = beanProps.split(",", -1); + Set userGroups = new HashSet(); + + JsonNode result = BeanFiller.getJmesResult(groupsJson, groupJsonPattern); + if ((result instanceof ArrayNode) && result.get(0) instanceof ObjectNode) { + throw new SemossPixelException("Group result must return flat array. Please check groupJsonPatter"); + } + for (int inputIndex = 0; result != null && inputIndex < result.size(); inputIndex++) { + String thisInput = result.get(inputIndex).asText(); + userGroups.add(thisInput); + } + + userObj.getAccessToken(AuthProvider.GITLAB).setUserGroups(userGroups); + userObj.getAccessToken(AuthProvider.GITLAB).setUserGroupType(AuthProvider.GITLAB.toString()); + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the GitLab authorization redirect URL. + * + * @param request inbound HTTP request + * @return GitLab authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getGitlabRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "gitlab_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String scope = socialData.getProperty(prefix + "scope"); + String auth_url = socialData.getProperty(prefix + "auth_url"); + + scope = scope.replaceAll(" ", "+"); + String state = UUID.randomUUID().toString(); + + String redirectUrl = auth_url + "?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" + + URLEncoder.encode(redirectUri, UTF8) + "&scope=" + scope + "&state=" + state; + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles Google OAuth login or connection callback flow. + * https://developers.google.com/api-client-library/java/google-api-java-client/oauth2 + */ + @GET + @Produces("application/json") + @Path("/login/google") + public Response loginGoogle(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + boolean loginAllowed = Boolean.TRUE.equals(socialData.getLoginsAllowed().get("google")); + boolean connectAllowed = Boolean.TRUE.equals(socialData.getConnectionsAllowed().get("google")); + + if (!loginAllowed && !connectAllowed) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "No actions are allowed for Google. Please contact your administrator."); + return WebUtility.getResponse(ret, 400); + } + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + boolean useLoginFlow = loginAllowed; + boolean useConnectionFlow = !useLoginFlow && connectAllowed; + if (useConnectionFlow && !hasLoggedInUser(userObj)) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Log in before connecting your Google account"); + return WebUtility.getResponse(ret, 401); + } + + String queryString = getEncodedQueryString(request); + + boolean needsLogin = useLoginFlow && !hasAccessToken(userObj, AuthProvider.GOOGLE); + boolean needsConnect = useConnectionFlow && !hasResourceAccessToken(userObj, AuthProvider.GOOGLE); + + if (hasOAuthCode(queryString)) { + if (needsLogin || needsConnect) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String prefix = "google_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + // I need to decode the return code from google since the default param's are + // encoded on the post of getAccessToken + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("grant_type", "authorization_code"); + params.put("client_secret", clientSecret); + + String url = "https://www.googleapis.com/oauth2/v4/token"; + + // https://developers.google.com/api-client-library/java/google-api-java-client/oauth2 + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getGoogleRedirect(request)); + return null; + } + accessToken.setProvider(AuthProvider.GOOGLE); + + // fill the access token with the other properties so we can properly create the + // user + GoogleTokenFiller profiler = new GoogleTokenFiller(); + profiler.fillAccessToken(accessToken, null, null, null, null); + + if (needsLogin) { + addAccessToken(accessToken, request, autoAdd); + } else { + addResourceAccessToken(accessToken, request); + } + + // Shows how to make a google credential from an access token + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (useConnectionFlow && !hasLoggedInUser(userObj)) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Log in before connecting your Google account"); + return WebUtility.getResponse(ret, 401); + } + if (useLoginFlow) { + if (!hasAccessToken(userObj, AuthProvider.GOOGLE)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getGoogleRedirect(request)); + return null; + } + } else if (!hasResourceAccessToken(userObj, AuthProvider.GOOGLE)) { + response.setStatus(302); + response.sendRedirect(getGoogleRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the Google authorization redirect URL. + * + * @param request inbound HTTP request + * @return Google authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getGoogleRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "google_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String scope = socialData.getProperty(prefix + "scope"); // need to set this up and reuse + String accessType = socialData.getProperty(prefix + "access_type"); // need to set this up and reuse + String state = UUID.randomUUID().toString(); + + String redirectUrl = "https://accounts.google.com/o/oauth2/v2/auth?" + "client_id=" + clientId + + "&response_type=code" + "&redirect_uri=" + URLEncoder.encode(redirectUri, UTF8) + "&access_type=" + + accessType + "&scope=" + URLEncoder.encode(scope, UTF8) + "&state=" + state; + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles Jira OAuth login callback and exchanges the authorization code for a + * token. + * + * @param request inbound HTTP request + * @param response outbound HTTP response + * @return redirect response + * @throws IOException when redirect writing fails + */ + @GET + @Produces("application/json") + @Path("/login2/jira") + public Response loginJiraDynamic(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.JIRA)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String state = URLDecoder.decode(outputs[1], StandardCharsets.UTF_8); + String connectionId = session == null ? null : (String) session.getAttribute("sf_state_" + state); + if (connectionId == null) { + // invalid or tampered state + response.setStatus(400); + return null; + } + session.removeAttribute("sf_state_" + state); + + String redirectUri = WebUtility.getCurrentCallbackUrl(request); + boolean autoAdd = true; + Map details = SecurityExternalConnectorsUtils + .getJiraConnectionDetails(connectionId); + String clientId = (String) details.get("clientId"); + String clientSecret = (String) details.get("clientSecret"); + String userInfoUrl = (String) details.get("userInfoUrl"); + + if (clientId == null || clientSecret == null || redirectUri == null) { + response.setStatus(400); + response.getWriter().write("Jira credentials not found for connection id = " + connectionId); + return null; + } + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("client_secret", clientSecret); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("grant_type", "authorization_code"); + + String url = "https://auth.atlassian.com/oauth/token"; + + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getJiraRedirectDynamic(request, response, connectionId)); + return null; + } + accessToken.setProvider(AuthProvider.JIRA); + // fill the access token with the other properties so we can properly create the + // user + JiraTokenFiller profiler = new JiraTokenFiller(); + profiler.fillAccessToken(accessToken, userInfoUrl, null, null, null); + + String cloudId = fetchJiraCloudId(accessToken.getAccess_token()); + if (cloudId != null) { + accessToken.setId(cloudId); + } + + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Successfully processed Jira OAuth callback. Access Token is.. {}", + accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.JIRA)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getJiraRedirectDynamic(request, response, null)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the Jira dynamic-credential authorization redirect URL. + * + * @param request inbound HTTP request + * @param response outbound HTTP response + * @param connectionId external-connector id + * @return Jira authorize URL or {@code null} when validation fails + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + * @throws IOException when response writing fails + */ + private String getJiraRedirectDynamic(HttpServletRequest request, HttpServletResponse response, String connectionId) + throws UnsupportedEncodingException, IOException { + String redirectUri = WebUtility.getCurrentCallbackUrl(request); + if (connectionId == null) { + connectionId = request.getParameter("connectionId"); + } + if (connectionId == null || connectionId.isEmpty()) { + response.setStatus(400); + response.getWriter().write("Missing required parameter: connectionId"); + return null; + } + + String state = UUID.randomUUID().toString(); + request.getSession().setAttribute("sf_state_" + state, connectionId); + + Map details = SecurityExternalConnectorsUtils.getJiraConnectionDetails(connectionId); + String clientId = (String) details.get("clientId"); + String scope = (String) details.get("scope"); + + if (clientId == null || scope == null || redirectUri == null) { + response.setStatus(400); + response.getWriter().write("Jira credentials not found for connection id = " + connectionId); + return null; + } + + String redirectUrl = "https://auth.atlassian.com/authorize" + "?audience=api.atlassian.com" + "&client_id=" + + URLEncoder.encode(clientId, "UTF-8") + "&scope=" + URLEncoder.encode(scope, "UTF-8") + + "&redirect_uri=" + URLEncoder.encode(redirectUri, "UTF-8") + "&state=" + + URLEncoder.encode(state, "UTF-8") + "&response_type=code" + "&prompt=consent"; + + classLogger.debug("Sending Jira redirect.. {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Fetches the first accessible Jira cloud resource id for a bearer token. + * + * @param bearerToken Jira bearer token + * @return cloud id when available; otherwise {@code null} + */ + private String fetchJiraCloudId(String bearerToken) { + try { + String url = "https://api.atlassian.com/oauth/token/accessible-resources"; + Map params = new HashMap<>(); + String output = HttpHelperUtility.makeGetCall(url, bearerToken, params, true); + JSONArray resources = new JSONArray(output); + if (resources.length() > 0) { + return resources.getJSONObject(0).getString("id"); + } + } catch (Exception e) { + classLogger.error("Failed to fetch Jira accessible resources (cloudId)", e); + } + return null; + } + + /** + * Handles LinkedIn OAuth login callback flow. + */ + @GET + @Produces("application/json") + @Path("/login/linkedin") + public Response loginLinkedin(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + if (socialData.getLoginsAllowed().get("linkedin") == null || !socialData.getLoginsAllowed().get("linkedin")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "LinkedIn login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.LINKEDIN)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String prefix = "linkedin_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("grant_type", "authorization_code"); + params.put("client_secret", clientSecret); + + String url = "https://www.linkedin.com/oauth/v2/accessToken"; + + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getLinkedinRedirect(request)); + return null; + } + accessToken.setProvider(AuthProvider.LINKEDIN); + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.LINKEDIN)) { + response.setStatus(302); + response.sendRedirect(getLinkedinRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the LinkedIn authorization redirect URL. + * + * @param request inbound HTTP request + * @return LinkedIn authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getLinkedinRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "linkedin_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String scope = socialData.getProperty(prefix + "scope"); + + String redirectUrl = "https://www.linkedin.com/oauth/v2/authorization?" + "client_id=" + clientId + + "&redirect_uri=" + redirectUri + "&state=" + UUID.randomUUID().toString() + "&response_type=code" + + "&scope=" + URLEncoder.encode(scope, UTF8); + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Deprecated alias for the Microsoft OAuth login endpoint. + */ + @GET + @Produces("application/json") + @Path("/login/ms") + @Deprecated + public Response loginMS(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + return loginMicrosoft(request, response); + } + + /** + * Handles Microsoft OAuth login callback flow. + * + * @param request inbound HTTP request + * @param response outbound HTTP response + * @return redirect response + * @throws IOException when redirect writing fails + */ + @GET + @Produces("application/json") + @Path("/login/microsoft") + public Response loginMicrosoft(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + if (socialData.getLoginsAllowed().get("ms") == null || !socialData.getLoginsAllowed().get("ms")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Microsoft login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.MICROSOFT)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String prefix = "ms_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String tenant = socialData.getProperty(prefix + "tenant"); + String scope = socialData.getProperty(prefix + "scope"); + String token_url = socialData.getProperty(prefix + "token_url"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + boolean login_external_allowed = Boolean + .parseBoolean(socialData.getProperty(prefix + "login_external")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("scope", scope); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("grant_type", "authorization_code"); + params.put("client_secret", clientSecret); + + if (Strings.isNullOrEmpty(token_url)) { + token_url = "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/token"; + } + + AccessToken accessToken = HttpHelperUtility.getAccessToken(token_url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getMicrosoftRedirect(request)); + return null; + } + + accessToken.setProvider(AuthProvider.MICROSOFT); + MicrosoftTokenFiller profiler = new MicrosoftTokenFiller(); + profiler.fillAccessToken(accessToken, null, null, null, null); + if (!login_external_allowed) { + if (accessToken.getName().contains("External")) { + accessToken = null; + throw new IllegalArgumentException("External users are not allowed"); + } + } + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.MICROSOFT)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getMicrosoftRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the Microsoft authorization redirect URL. + * + * @param request inbound HTTP request + * @return Microsoft authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getMicrosoftRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "ms_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String tenant = socialData.getProperty(prefix + "tenant"); + String scope = socialData.getProperty(prefix + "scope"); // need to set this up and reuse + String auth_url = socialData.getProperty(prefix + "auth_url"); + + String state = UUID.randomUUID().toString(); + + if (Strings.isNullOrEmpty(auth_url)) { + auth_url = "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/authorize"; + } + String redirectUrl = auth_url + "?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" + + URLEncoder.encode(redirectUri, UTF8) + "&response_mode=query" + "&scope=" + + URLEncoder.encode(scope, UTF8) + "&state=" + state; + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles Okta OAuth login callback flow. + */ + @GET + @Produces("application/json") + @Path("/login/okta") + public Response loginOkta(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + if (socialData.getLoginsAllowed().get("okta") == null || !socialData.getLoginsAllowed().get("okta")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Okta login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.MICROSOFT)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String prefix = "okta_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String scope = socialData.getProperty(prefix + "scope"); + String token_url = socialData.getProperty(prefix + "token_url"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("scope", scope); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("grant_type", "authorization_code"); + params.put("client_secret", clientSecret); + + AccessToken accessToken = HttpHelperUtility.getAccessToken(token_url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getOktaRedirect(request)); + return null; + } + + accessToken.setProvider(AuthProvider.OKTA); + + // sub is the unique id for a user in okta + String userinfo_url = socialData.getProperty(prefix + "userinfo_url"); + String beanProps = socialData.getProperty(prefix + "beanProps"); + String[] beanPropsArr = beanProps.split(",", -1); + String jsonPattern = socialData.getProperty(prefix + "jsonPattern"); + + OktaTokenFiller profiler = new OktaTokenFiller(); + profiler.fillAccessToken(accessToken, userinfo_url, jsonPattern, beanPropsArr, null); + addAccessToken(accessToken, request, autoAdd); + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.OKTA)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getOktaRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the Okta authorization redirect URL. + * + * @param request inbound HTTP request + * @return Okta authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getOktaRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "okta_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String scope = socialData.getProperty(prefix + "scope"); // need to set this up and reuse + String auth_url = socialData.getProperty(prefix + "auth_url"); + String state = UUID.randomUUID().toString(); + + String redirectUrl = auth_url + "?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" + + URLEncoder.encode(redirectUri, UTF8) + "&response_mode=query" + "&scope=" + + URLEncoder.encode(scope, UTF8) + "&state=" + state; + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + @Path("/login/producthunt") + /** + * Handles Product Hunt OAuth login callback flow. + * + * @param request inbound HTTP request + * @param response outbound HTTP response + * @return redirect response + * @throws IOException when redirect writing fails + */ + public Response loginProducthunt(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + if (socialData.getLoginsAllowed().get("producthunt") == null + || !socialData.getLoginsAllowed().get("producthunt")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Producthunt login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.PRODUCT_HUNT)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String prefix = "producthunt_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("grant_type", "authorization_code"); + params.put("client_secret", clientSecret); + + String url = "https://api.producthunt.com/v1/oauth/token"; + + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getProducthuntRedirect(request)); + return null; + } + accessToken.setProvider(AuthProvider.PRODUCT_HUNT); + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.PRODUCT_HUNT)) { + response.setStatus(302); + response.sendRedirect(getProducthuntRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the Product Hunt authorization redirect URL. + * + * @param request inbound HTTP request + * @return Product Hunt authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getProducthuntRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "producthunt_"; + + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String scope = socialData.getProperty(prefix + "scope"); + + String redirectUrl = "https://api.producthunt.com/v1/oauth/authorize?" + "client_id=" + clientId + + "&response_type=code" + "&redirect_uri=" + URLEncoder.encode(redirectUri, UTF8) + "&scope=" + + URLEncoder.encode(scope, UTF8); + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles Salesforce OAuth login callback flow. + */ + @GET + @Produces("application/json") + @Path("/login/salesforce") + public Response loginSalesforce(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + if (socialData.getLoginsAllowed().get("salesforce") == null + || !socialData.getLoginsAllowed().get("salesforce")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Salesforce login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.SALESFORCE)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String prefix = "salesforce_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("grant_type", "authorization_code"); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("client_secret", clientSecret); + + String url = "https://login.salesforce.com/services/oauth2/token"; + + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getSalesforceRedirect(request)); + return null; + } + accessToken.setProvider(AuthProvider.SALESFORCE); + + // fill the access token with the other properties so we can properly create the + // user + SalesforceTokenFiller profiler = new SalesforceTokenFiller(); + profiler.fillAccessToken(accessToken, null, null, null, null); + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.SALESFORCE)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getSalesforceRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the Salesforce authorization redirect URL. + * + * @param request inbound HTTP request + * @return Salesforce authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getSalesforceRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "salesforce_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + + String redirectUrl = "https://login.salesforce.com/services/oauth2/authorize?" + "client_id=" + clientId + + "&response_type=code" + "&redirect_uri=" + redirectUri + "&scope=" + URLEncoder.encode("api", UTF8); + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles Salesforce OAuth callback flow using dynamic connector credentials. + */ + @GET + @Produces("application/json") + @Path("/login2/salesforce") + public Response loginSalesforceDynamic(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.SALESFORCE)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String state = outputs[1]; + String connectionId = session == null ? null : (String) session.getAttribute("sf_state_" + state); + if (connectionId == null) { + // invalid or tampered state + response.setStatus(400); + return null; + } + session.removeAttribute("sf_state_" + state); + + // get credentials by UUID (ID) from SALESFORCE_CREDENTIALS table + String redirectUri = WebUtility.getCurrentCallbackUrl(request); + boolean autoAdd = true; + + Pair details = SecurityExternalConnectorsUtils + .getSalesforceConnectionDetails(connectionId); + String clientId = details.getValue0(); + String clientSecret = details.getValue1(); + + if (clientId == null || clientSecret == null || redirectUri == null) { + response.setStatus(400); + response.getWriter() + .write("Salesforce credentials not found for connection id = " + connectionId); + return null; + } + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("grant_type", "authorization_code"); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("client_secret", clientSecret); + + String url = "https://login.salesforce.com/services/oauth2/token"; + + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getSalesforceRedirectDynamic(request, response, connectionId)); + return null; + } + accessToken.setProvider(AuthProvider.SALESFORCE); + + // fill the access token with the other properties so we can properly create the + // user + SalesforceTokenFiller profiler = new SalesforceTokenFiller(); + profiler.fillAccessToken(accessToken, null, null, null, null); + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.SALESFORCE)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getSalesforceRedirectDynamic(request, response, null)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the Salesforce dynamic-credential authorization redirect URL. + * + * @param request inbound HTTP request + * @param response outbound HTTP response + * @param connectionId external-connector id + * @return Salesforce authorize URL or {@code null} when validation fails + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + * @throws IOException when response writing fails + */ + private String getSalesforceRedirectDynamic(HttpServletRequest request, @Context HttpServletResponse response, + String connectionId) throws UnsupportedEncodingException, IOException { + String redirectUri = WebUtility.getCurrentCallbackUrl(request); + if (connectionId == null) { + connectionId = request.getParameter("connectionId"); + } + if (connectionId == null || connectionId.isEmpty()) { + response.setStatus(400); + response.getWriter().write("Missing required parameter: connectionId"); + return null; + } + + String state = UUID.randomUUID().toString(); + // store the connection id in session + request.getSession().setAttribute("sf_state_" + state, connectionId); + + Pair details = SecurityExternalConnectorsUtils.getSalesforceConnectionDetails(connectionId); + String clientId = details.getValue0(); + String redirectUrl = "https://login.salesforce.com/services/oauth2/authorize?" + "client_id=" + + URLEncoder.encode(clientId, "UTF-8") + "&response_type=code" + "&redirect_uri=" + + URLEncoder.encode(redirectUri, "UTF-8") + "&scope=" + URLEncoder.encode("api", "UTF-8") + "&state=" + + state; + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles ServiceNow OAuth login callback flow. + */ + @GET + @Produces("application/json") + @Path("/login/servicenow") + public Response loginServiceNow(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + if (socialData.getLoginsAllowed().get("servicenow") == null + || !socialData.getLoginsAllowed().get("servicenow")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Servicenow login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.SERVICENOW)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String prefix = "servicenow_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String instanceUrl = socialData.getProperty(prefix + "instance_url"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("grant_type", "authorization_code"); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("client_secret", clientSecret); + + String url = instanceUrl + "/oauth_token.do"; + + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getServiceNowRedirect(request)); + return null; + } + accessToken.setProvider(AuthProvider.SERVICENOW); + + // fill the access token with the other properties so we can properly create the + // user + ServiceNowTokenFiller profiler = new ServiceNowTokenFiller(); + profiler.fillAccessToken(accessToken, null, null, null, null); + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.SERVICENOW)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getServiceNowRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the ServiceNow authorization redirect URL. + * + * @param request inbound HTTP request + * @return ServiceNow authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getServiceNowRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "servicenow_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String instanceUrl = socialData.getProperty(prefix + "instance_url"); + + String redirectUrl = instanceUrl + "/oauth_auth.do?" + "client_id=" + clientId + "&response_type=code" + + "&redirect_uri=" + redirectUri; + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles ServiceNow OAuth callback flow using dynamic connector credentials. + */ + @GET + @Produces("application/json") + @Path("/login2/servicenow") + public Response loginServiceNowDynamic(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.SERVICENOW)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String state = outputs[1]; + String connectionId = session == null ? null : (String) session.getAttribute("sn_state_" + state); + if (connectionId == null) { + // invalid or tampered state + response.setStatus(400); + return null; + } + session.removeAttribute("sn_state_" + state); + + // get credentials by UUID (ID) from SERVICENOW_CREDENTIALS table + String redirectUri = WebUtility.getCurrentCallbackUrl(request); + boolean autoAdd = true; + + Map details = SecurityExternalConnectorsUtils + .getServiceNowConnectionDetails(connectionId); + String instanceUrl = details.get("instanceUrl"); + String clientId = details.get("clientId"); + String clientSecret = details.get("clientSecret"); + String userInfoUrl = details.get("userProfileUrl"); // to pass to fillAccessToken method + + if (instanceUrl == null || clientId == null || clientSecret == null || redirectUri == null) { + response.setStatus(400); + response.getWriter() + .write("ServiceNow credentials not found for connection id =" + connectionId); + return null; + } + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("grant_type", "authorization_code"); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("client_secret", clientSecret); + + String url = instanceUrl + "/oauth_token.do"; + + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getServiceNowRedirectDynamic(request, response, connectionId)); + return null; + } + accessToken.setProvider(AuthProvider.SERVICENOW); + + // fill the access token with the other properties so we can properly create the + // user + ServiceNowTokenFiller profiler = new ServiceNowTokenFiller(); + profiler.fillAccessToken(accessToken, userInfoUrl, null, null, null); + + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.SERVICENOW)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getServiceNowRedirectDynamic(request, response, null)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the ServiceNow dynamic-credential authorization redirect URL. + * + * @param request inbound HTTP request + * @param response outbound HTTP response + * @param connectionId external-connector id + * @return ServiceNow authorize URL or {@code null} when validation fails + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + * @throws IOException when response writing fails + */ + private String getServiceNowRedirectDynamic(HttpServletRequest request, @Context HttpServletResponse response, + String connectionId) throws UnsupportedEncodingException, IOException { + String redirectUri = WebUtility.getCurrentCallbackUrl(request); + if (connectionId == null) { + connectionId = request.getParameter("connectionId"); + } + if (connectionId == null || connectionId.isEmpty()) { + response.setStatus(400); + response.getWriter().write("Missing required parameter: connectionId"); + return null; + } + + String state = UUID.randomUUID().toString(); + // store the connection id in session + request.getSession().setAttribute("sn_state_" + state, connectionId); + + Map details = SecurityExternalConnectorsUtils.getServiceNowConnectionDetails(connectionId); + String instanceUrl = details.get("instanceUrl"); + String clientId = details.get("clientId"); + + String redirectUrl = instanceUrl + "/oauth_auth.do?" + "client_id=" + URLEncoder.encode(clientId, "UTF-8") + + "&response_type=code" + "&redirect_uri=" + URLEncoder.encode(redirectUri, "UTF-8") + "&state=" + + state; + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles SiteMinder OAuth login callback flow. + */ + @GET + @Produces("application/json") + @Path("/login/siteminder") + public Response loginSiteminder(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + if (socialData.getLoginsAllowed().get("siteminder") == null + || !socialData.getLoginsAllowed().get("siteminder")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Siteminder login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.SITEMINDER)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String prefix = "siteminder_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String tenant = socialData.getProperty(prefix + "tenant"); + String scope = socialData.getProperty(prefix + "scope"); + String token_url = socialData.getProperty(prefix + "token_url"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("scope", scope); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("grant_type", "authorization_code"); + params.put("client_secret", clientSecret); + + if (Strings.isNullOrEmpty(token_url)) { + token_url = "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/token"; + } + AccessToken accessToken = HttpHelperUtility.getAccessToken(token_url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getSiteminderRedirect(request)); + return null; + } + + accessToken.setProvider(AuthProvider.SITEMINDER); + addAccessToken(accessToken, request, autoAdd); + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.SITEMINDER)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getSiteminderRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the SiteMinder authorization redirect URL. + * + * @param request inbound HTTP request + * @return SiteMinder authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getSiteminderRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "siteminder_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String tenant = socialData.getProperty(prefix + "tenant"); + String scope = socialData.getProperty(prefix + "scope"); // need to set this up and reuse + String auth_url = socialData.getProperty(prefix + "auth_url"); + String state = UUID.randomUUID().toString(); + + if (Strings.isNullOrEmpty(auth_url)) { + auth_url = "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/authorize"; + } + + String redirectUrl = auth_url + "?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" + + URLEncoder.encode(redirectUri, UTF8) + "&response_mode=query" + "&scope=" + + URLEncoder.encode(scope, UTF8) + "&state=" + state; + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles SurveyMonkey OAuth login callback flow. + */ + @GET + @Produces("application/json") + @Path("/login/surveymonkey") + public Response loginSurveyMonkey(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + if (socialData.getLoginsAllowed().get("surveymonkey") == null + || !socialData.getLoginsAllowed().get("surveymonkey")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Surveymonkey login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.SURVEYMONKEY)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String prefix = "surveymonkey_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("grant_type", "authorization_code"); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("client_secret", clientSecret); + + String url = "https://api.surveymonkey.com/oauth/token"; + + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getSurveyMonkeyRedirect(request)); + return null; + } + accessToken.setProvider(AuthProvider.SURVEYMONKEY); + MonkeyProfile.fillAccessToken(accessToken, null); + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.SURVEYMONKEY)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getSurveyMonkeyRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the SurveyMonkey authorization redirect URL. + * + * @param request inbound HTTP request + * @return SurveyMonkey authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getSurveyMonkeyRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "surveymonkey_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + + String redirectUrl = "https://api.surveymonkey.com/oauth/authorize?" + "client_id=" + clientId + + "&response_type=code" + "&redirect_uri=" + redirectUri; + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles Twitter OAuth login callback flow. + * + * @param request + * @param response + * @return + * @throws IOException + */ + @GET + @Produces("application/json") + @Path("/login/twitter") + public Response loginTwitter(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws IOException { + if (socialData.getLoginsAllowed().get("twitter") == null || !socialData.getLoginsAllowed().get("twitter")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Twitter login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + // getting the bearer token on twitter for app authentication is a lot simpler + // need to just combine the id and secret + // base 64 and send as authorization + + // https://developer.github.com/apps/building-oauth-apps/authorization-options-for-oauth-apps/ + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, AuthProvider.GITHUB)) { + + String[] outputs = HttpHelperUtility.getCodes(queryString); + // oauth code and state should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.5 + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + String state = URLDecoder.decode(outputs[1], StandardCharsets.UTF_8); + if (code.matches("[ -~]+") && state.matches("[ -~]+")) { + String prefix = "twitter_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("state", state); + params.put("client_secret", clientSecret); + + String url = "https://api.twitter.com/oauth/access_token"; + + AccessToken accessToken = HttpHelperUtility.getAccessToken(url, params, false, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getTwitterRedirect(request)); + return null; + } + + accessToken.setProvider(AuthProvider.TWITTER); + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, AuthProvider.TWITTER)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getTwitterRedirect(request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the Twitter authorization redirect URL. + * + * @param request inbound HTTP request + * @return Twitter authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getTwitterRedirect(HttpServletRequest request) throws UnsupportedEncodingException { + String prefix = "twitter_"; + + String clientId = socialData.getProperty(prefix + "client_id"); + // String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + String scope = socialData.getProperty(prefix + "scope"); + String nonce = UUID.randomUUID().toString(); + String timestamp = System.currentTimeMillis() + ""; + + StringBuffer signatureString = new StringBuffer("GET").append("&"); + signatureString.append(URLEncoder.encode("https://api.twitter.com/oauth/authorize", UTF8)).append("&"); + + StringBuffer parameterString = new StringBuffer(""); + parameterString.append("oauth_callback=").append(URLEncoder.encode(redirectUri, UTF8)).append("&"); + parameterString.append("oauth_consumer_key=").append(clientId).append("&"); + parameterString.append("oauth_nonce=").append(nonce).append("&"); + parameterString.append("oauth_timestamp=").append(timestamp); + + // String finalString = signatureString.toString() + parameterString.toString(); + + // String signature = + + String redirectUrl = "https://github.com/login/oauth/authorize?" + "oauth_consumer_key=" + clientId + + "&oauth_callback=" + redirectUri + "&oauth_nonce=" + nonce + "&oauth_timestamp=" + timestamp + + "&scope=" + URLEncoder.encode(scope, UTF8); + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + /** + * Handles OAuth login callback flow for a generic provider. + */ + @GET + @Produces("application/json") + @Path("/login/{provider}") + public Response loginGeneric(@PathParam("provider") String provider, @Context HttpServletRequest request, + @Context HttpServletResponse response) throws IOException { + provider = WebUtility.inputSanitizer(provider); + if (socialData.getLoginsAllowed().get(provider) == null || !socialData.getLoginsAllowed().get(provider)) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, provider + " login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + AuthProvider providerEnum = AuthProvider.getProviderFromString(provider.toUpperCase()); + + HttpSession session = initializeOAuthLoginSession(request); + User userObj = getSessionUser(session); + String queryString = getEncodedQueryString(request); + if (hasOAuthCode(queryString)) { + if (!hasAccessToken(userObj, providerEnum)) { + String[] outputs = HttpHelperUtility.getCodes(queryString); + + // oauth code should match [ -~]+ (1 or more ascii) + // https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11 + String code = URLDecoder.decode(outputs[0], StandardCharsets.UTF_8); + if (code.matches("[ -~]+")) { + String prefix = provider + "_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String clientSecret = socialData.getProperty(prefix + "secret_key"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty(prefix + "auto_add", "true")); + // String tenant = socialData.getProperty(prefix + "tenant"); + + // removing scope for now as it isn't needed in token call usually + // String scope = socialData.getProperty(prefix + "scope"); + String token_url = socialData.getProperty(prefix + "token_url"); + + classLogger.debug(">> {}", Utility.cleanLogString(request.getQueryString())); + + Map params = new HashMap<>(); + params.put("client_id", clientId); + // params.put("scope", scope); + params.put("redirect_uri", redirectUri); + params.put("code", code); + params.put("grant_type", "authorization_code"); + params.put("client_secret", clientSecret); + + if (Strings.isNullOrEmpty(token_url)) { + throw new IllegalArgumentException("Token URL can not be null or empty"); + } + + AccessToken accessToken = HttpHelperUtility.getAccessToken(token_url, params, true, true); + if (accessToken == null) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getGenericRedirect(provider, request)); + return null; + } + + String userInfoURL = socialData.getProperty(prefix + "userinfo_url"); + // "name","id","email" + String beanProps = socialData.getProperty(prefix + "beanProps"); + String[] beanPropsArr = beanProps.split(",", -1); + String jsonPattern = socialData.getProperty(prefix + "jsonPattern"); + + accessToken.setProvider(providerEnum); + + // this is a check for sanitizing a response back from an IAM provider - not + // common and should be false + // examples would be unescaped special chars in the response that then can't be + // parsed into a json. + // this is not very common. + boolean sanitizeResponse = Boolean + .parseBoolean(socialData.getProperty(prefix + "sanitizeUserResponse")); + + GenericTokenFiller profiler = new GenericTokenFiller(); + profiler.fillAccessToken(accessToken, userInfoURL, jsonPattern, beanPropsArr, null, + sanitizeResponse); + + if (Boolean.parseBoolean(socialData.getProperty(prefix + "groups"))) { + // get groups + String group_url = socialData.getProperty(prefix + "group_url"); + // make the call to get the groups + String groupsJson = HttpHelperUtility.makeGetCall(group_url, accessToken.getAccess_token()); + // this is a check for sanitizing a response back from an IAM provider - not + // common and should be false + // examples would be unescaped special chars in the response that then can't be + // parsed into a json. + boolean sanitizeGroupResponse = Boolean + .parseBoolean(socialData.getProperty(prefix + "sanitizeGroupResponse")); + if (sanitizeGroupResponse) { + groupsJson = groupsJson.replace("\\", "\\\\"); + // add more replacements as need be in the future + } + + Set userGroups = new HashSet(); + // are groups returned as a single string or an array in a json. Usually it is + // an array in a json. + boolean groupStringResponse = Boolean + .parseBoolean(socialData.getProperty(prefix + "group_string_return")); + if (groupStringResponse) { + // this json pattern should return a single string with groups concat + // ""fakeGroups":"CN=group1, CN=group2, CN=group3" + String groupJsonPattern = socialData.getProperty(prefix + "groupJsonPattern"); + JsonNode result = BeanFiller.getJmesResult(groupsJson, groupJsonPattern); + try { + // get the single string and the regex pattern. validate the pattern + String groupText = result.asText(); + String regexPattern = socialData.getProperty(prefix + "group_string_regex"); + try { + Pattern pattern = Pattern.compile(regexPattern); + } catch (PatternSyntaxException e) { + classLogger.error("Unexpected error in loginGeneric", e); + throw new SemossPixelException("Pattern input is not a valid regex"); + } + + // split the groups + String[] groups = groupText.split(regexPattern); + for (String group : groups) { + userGroups.add(group); + } + } catch (Exception e) { + classLogger.error("Unexpected error in loginGeneric", e); + throw new SemossPixelException("Could not parse response as string"); + } + + } else { + // this json pattern should return an array + String groupJsonPattern = socialData.getProperty(prefix + "groupJsonPattern"); + JsonNode result = BeanFiller.getJmesResult(groupsJson, groupJsonPattern); + if ((result instanceof ArrayNode) && result.get(0) instanceof ObjectNode) { + throw new SemossPixelException( + "Group result must return flat array. Please check groupJsonPatter"); + } + for (int inputIndex = 0; result != null && inputIndex < result.size(); inputIndex++) { + String thisInput = result.get(inputIndex).asText(); + userGroups.add(thisInput); + } + } + + accessToken.setUserGroups(userGroups); + accessToken.setUserGroupType(providerEnum.toString()); + } + + addAccessToken(accessToken, request, autoAdd); + + classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); + } + } + } + + userObj = refreshSessionUser(request, session); + if (!hasAccessToken(userObj, providerEnum)) { + // not authenticated + response.setStatus(302); + response.sendRedirect(getGenericRedirect(provider, request)); + return null; + } + + setMainPageRedirect(request, response); + return null; + } + + /** + * Builds the generic provider authorization redirect URL. + * + * @param provider provider key from social properties + * @param request inbound HTTP request + * @return provider authorize URL + * @throws UnsupportedEncodingException when redirect parameters cannot be URL + * encoded + */ + private String getGenericRedirect(String provider, HttpServletRequest request) throws UnsupportedEncodingException { + provider = WebUtility.inputSanitizer(provider); + String prefix = provider + "_"; + String clientId = socialData.getProperty(prefix + "client_id"); + String redirectUri = socialData.getProperty(prefix + "redirect_uri"); + // String tenant = socialData.getProperty(prefix + "tenant"); + String scope = socialData.getProperty(prefix + "scope"); // need to set this up and reuse + String auth_url = socialData.getProperty(prefix + "auth_url"); + + String state = UUID.randomUUID().toString(); + + if (Strings.isNullOrEmpty(auth_url)) { + throw new IllegalArgumentException("Authorize URL can not be null or empty"); + } + + String redirectUrl; + + // are you already adding custom props? if so I will skip adding the ? + if (auth_url.contains("?")) { + redirectUrl = auth_url + "&client_id=" + clientId + "&response_type=code" + "&redirect_uri=" + + URLEncoder.encode(redirectUri, UTF8) + "&response_mode=query" + "&scope=" + + URLEncoder.encode(scope, UTF8) + "&state=" + state; + } else { + redirectUrl = auth_url + "?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" + + URLEncoder.encode(redirectUri, UTF8) + "&response_mode=query" + "&scope=" + + URLEncoder.encode(scope, UTF8) + "&state=" + state; + } + + classLogger.debug("Sending redirect {}", Utility.cleanLogString(redirectUrl)); + return redirectUrl; + } + + ///////////////////////////////////////////////////////////////// + + /** + * This portion of code is for semoss generated users + */ + + /** + * Authenticates a native user with username and password credentials. + * + * @param request + * @return true if the information provided to log in is valid otherwise error. + */ + @POST + @Produces("application/json") + @Path("/login") + public Response loginNative(@Context HttpServletRequest request, @Context HttpServletResponse response) { + Map ret = new HashMap<>(); + + if (socialData.getLoginsAllowed().get("native") == null || !socialData.getLoginsAllowed().get("native")) { + ret.put(Constants.ERROR_MESSAGE, "Native login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + try { + String username = WebUtility.inputSQLSanitizer(request.getParameter("username")); + String password = WebUtility.inputSQLSanitizer(request.getParameter("password")); + String redirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); + // so that the default is to redirect + Boolean disableRedirect = Boolean.parseBoolean(request.getParameter("disableRedirect") + ""); + + if (username == null || password == null || username.isEmpty() || password.isEmpty()) { + classLogger.warn("User is trying to login using username='{}' but user name or password are empty", + username); + ret.put(Constants.ERROR_MESSAGE, "The user name or password are empty"); + return WebUtility.getResponse(ret, 401); + } + + boolean canLogin = SecurityNativeUserUtils.logIn(username, password); + if (canLogin) { + String name = SecurityNativeUserUtils.getNameUser(username); + String email = SecurityNativeUserUtils.getUserEmail(username); + + String id = SecurityNativeUserUtils.getUserId(username); + AccessToken authToken = new AccessToken(); + authToken.setProvider(AuthProvider.NATIVE); + authToken.setId(id); + authToken.setName(name); + authToken.setUsername(username); + authToken.setEmail(email); + // no need to auto-add since to login native you must already exist + addAccessToken(authToken, request, false); + + // add these to the return + ret.put("success", "true"); + ret.put("username", username); + ret.put("name", name); + ret.put("email", email); + + // log the log in + if (!disableRedirect) { + setMainPageRedirect(request, response, redirect); + } + } else { + HttpSession session = request.getSession(false); + User user = null; + if (session != null) { + user = (User) session.getAttribute(Constants.SESSION_USER); + if (!AbstractSecurityUtils.anonymousUsersEnabled() && user != null && user.getLogins().isEmpty()) { + session.invalidate(); + } + } + classLogger.warn("User is trying to login using username='{}' but user name or password are empty", + username); + ret.put(Constants.ERROR_MESSAGE, "The user name or password are invalid."); + return WebUtility.getResponse(ret, 401); + } + } catch (Exception e) { + HttpSession session = request.getSession(false); + if (session != null) { + User user = (User) session.getAttribute(Constants.SESSION_USER); + if (!AbstractSecurityUtils.anonymousUsersEnabled() && user != null && user.getLogins().isEmpty()) { + session.invalidate(); + } + } + classLogger.error("Unexpected error in loginNative", e); + ret.put(Constants.ERROR_MESSAGE, "An unexpected error happened. Please try again."); + return WebUtility.getResponse(ret, 500); + } + + return WebUtility.getResponse(ret, 200); + } + + /** + * Authenticates a user with LDAP credentials. + * + * @param request + * @return true if the information provided to log in is valid otherwise error. + */ + @POST + @Produces("application/json") + @Path("/loginLDAP") + public Response loginLDAP(@Context HttpServletRequest request, @Context HttpServletResponse response) { + Map ret = new HashMap<>(); + if (socialData.getLoginsAllowed().get("ldap") == null || !socialData.getLoginsAllowed().get("ldap")) { + ret.put(Constants.ERROR_MESSAGE, "LDAP login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + ILdapAuthenticator authenticator = null; + try { + String username = WebUtility.inputSQLSanitizer(request.getParameter("username")); + String password = WebUtility.inputSQLSanitizer(request.getParameter("password")); + // so that the default is to redirect + Boolean disableRedirect = Boolean.parseBoolean(request.getParameter("disableRedirect") + ""); + + if (username == null || password == null || username.isEmpty() || password.isEmpty()) { + ret.put(Constants.ERROR_MESSAGE, "The user name or password are empty"); + return WebUtility.getResponse(ret, 401); + } + + authenticator = socialData.getLdapAuthenticator(); + AccessToken authToken = authenticator.authenticate(username, password); + if (authToken == null) { + throw new IllegalArgumentException("Unable to parse any user attributes"); + } + boolean autoAdd = Boolean + .parseBoolean(socialData.getProperty(ILdapAuthenticator.LDAP + "auto_add", "true")); + addAccessToken(authToken, request, autoAdd); + ret.put("success", "true"); + ret.put("username", username); + // log the log in + if (!disableRedirect) { + setMainPageRedirect(request, response); + } + } catch (LDAPPasswordChangeRequiredException e) { + HttpSession session = request.getSession(false); + if (session != null) { + User user = (User) session.getAttribute(Constants.SESSION_USER); + if (!AbstractSecurityUtils.anonymousUsersEnabled() && user != null && user.getLogins().isEmpty()) { + session.invalidate(); + } + } + classLogger.error("Unexpected error in loginLDAP", e); + ret.put(Constants.ERROR_MESSAGE, "User must change their password before login"); + ret.put(ILdapAuthenticator.LDAP_PASSWORD_CHANGE_RETURN_KEY, true); + return WebUtility.getResponse(ret, 401); + } catch (Exception e) { + HttpSession session = request.getSession(false); + if (session != null) { + User user = (User) session.getAttribute(Constants.SESSION_USER); + if (!AbstractSecurityUtils.anonymousUsersEnabled() && user != null && user.getLogins().isEmpty()) { + session.invalidate(); + } + } + classLogger.error("Unexpected error in loginLDAP", e); + ret.put(Constants.ERROR_MESSAGE, e.getMessage()); + return WebUtility.getResponse(ret, 500); + } finally { + if (authenticator != null) { + try { + authenticator.close(); + } catch (IOException e) { + classLogger.error("Unexpected error in loginLDAP", e); + } + } + } + + return WebUtility.getResponse(ret, 200); + } + + /** + * Changes an Active Directory user password. + * + * @param request + * @return true if the information provided to log in is valid otherwise error. + */ + @POST + @Produces("application/json") + @Path("/changeADPassword") + public Response changeADPassword(@Context HttpServletRequest request, @Context HttpServletResponse response) { + Map ret = new HashMap<>(); + if ((socialData.getLoginsAllowed().get("ldap") == null || !socialData.getLoginsAllowed().get("ldap")) + && !Boolean.parseBoolean(socialData.getProperty("linotp_check_ad", "false"))) { + ret.put(Constants.ERROR_MESSAGE, "LDAP change password is not allowed/configured"); + return WebUtility.getResponse(ret, 400); + } + + ILdapAuthenticator authenticator = null; + try { + String username = WebUtility.inputSQLSanitizer(request.getParameter("username")); + String curPassword = WebUtility.inputSQLSanitizer(request.getParameter("curPassword")); + String newPassword = WebUtility.inputSQLSanitizer(request.getParameter("newPassword")); + + if (username == null || curPassword == null || newPassword == null || username.isEmpty() + || curPassword.isEmpty() || newPassword.isEmpty()) { + ret.put(Constants.ERROR_MESSAGE, "The user name, current password, or new password are empty"); + return WebUtility.getResponse(ret, 401); + } + + authenticator = socialData.getLdapAuthenticator(); + authenticator.updateUserPassword(username, curPassword, newPassword); + ret.put("success", "true"); + ret.put("username", username); + return WebUtility.getResponse(ret, 200); + } catch (Exception e) { + HttpSession session = request.getSession(false); + if (session != null) { + User user = (User) session.getAttribute(Constants.SESSION_USER); + if (!AbstractSecurityUtils.anonymousUsersEnabled() && user != null && user.getLogins().isEmpty()) { + session.invalidate(); + } + } + classLogger.error("Unexpected error in changeADPassword", e); + ret.put(Constants.ERROR_MESSAGE, e.getMessage()); + return WebUtility.getResponse(ret, 500); + } finally { + if (authenticator != null) { + try { + authenticator.close(); + } catch (IOException e) { + classLogger.error("Unexpected error in changeADPassword", e); + } + } + } + } + + /** + * Authenticates a user by validating LinOTP one-time passcodes. + * + * @param request + * @return true if the information provided to log in is valid otherwise error. + * @throws IOException + * @throws ClientProtocolException + */ + @POST + @Produces("application/json") + @Path("/loginLinOTP") + public Response loginLinOTP(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws ClientProtocolException, IOException { + Map returnMap = new HashMap<>(); + if (socialData.getLoginsAllowed().get("linotp") == null || !socialData.getLoginsAllowed().get("linotp")) { + returnMap.put(Constants.ERROR_MESSAGE, "LinOTP login is not allowed"); + return WebUtility.getResponse(returnMap, 400); + } + + String redirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); + // so that the default is to redirect + Boolean disableRedirect = Boolean.parseBoolean(request.getParameter("disableRedirect") + ""); + boolean autoAdd = Boolean.parseBoolean(socialData.getProperty("linotp_auto_add", "true")); + + LinOTPResponse linotpResponse = LinOTPUtil.login(request); + returnMap = linotpResponse.getReturnMap(); + int responseCode = linotpResponse.getResponseCode(); + if (responseCode != 200) { + // we just throw the error + return WebUtility.getResponse(returnMap, responseCode); + } else { + // are we logged in? + AccessToken token = linotpResponse.getToken(); + if (token == null) { + // it is a 200 but we are not logged in + // you likely need to enter otp in 2nd response + return WebUtility.getResponse(returnMap, responseCode); + } + + // we have a login + addAccessToken(token, request, autoAdd); + // log the log in + if (!disableRedirect) { + setMainPageRedirect(request, response, redirect); + } + + return WebUtility.getResponse(returnMap, 200); + } + + } + + /** + * Resets LinOTP failed-attempt counters for a user. + * + * @param request + * @return true if the information provided to log in is valid otherwise error. + * @throws IOException + * @throws ClientProtocolException + */ + @POST + @Produces("application/json") + @Path("/resetLinOTPFailCounter") + public Response resetLinOTPFailCounter(@Context HttpServletRequest request, @Context HttpServletResponse response) + throws ClientProtocolException, IOException { + try { + LinOTPResponse linotpResponse = LinOTPUtil.resetCounter(request); + Map returnMap = linotpResponse.getReturnMap(); + int responseCode = linotpResponse.getResponseCode(); + // this is simple, take response code and message and return + return WebUtility.getResponse(returnMap, responseCode); + } catch (Exception e) { + classLogger.error("Unexpected error in resetLinOTPFailCounter", e); + Map errorMessage = new HashMap<>(); + errorMessage.put(Constants.ERROR_MESSAGE, + "Error occurred resetting the pin. Error message = " + e.getMessage()); + return WebUtility.getResponse(errorMessage, 500); + } + } + + /** + * Creates a native platform user. email) + * + * @param request + * @return true if the user is created otherwise error. + */ + @POST + @Produces("application/json") + @Path("createUser") + public Response createNativeUser(@Context HttpServletRequest request) { + Map ret = new HashMap<>(); + + if (socialData.getLoginsAllowed().get("native") == null || !socialData.getLoginsAllowed().get("native")) { + ret.put(Constants.ERROR_MESSAGE, "Native login is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + if (socialData.getLoginsAllowed().get("registration") == null + || !socialData.getLoginsAllowed().get("registration")) { + ret.put(Constants.ERROR_MESSAGE, "Native registration is not allowed"); + return WebUtility.getResponse(ret, 400); + } + + // get the connection to RDF_MAP.prop file to get the user default set values + try { + // Note - for native users + // the id and the username are always the same + String username = WebUtility.inputSQLSanitizer(request.getParameter("username")); + String name = WebUtility.inputSQLSanitizer(request.getParameter("name")); + String password = WebUtility.inputSQLSanitizer(request.getParameter("password")); + String email = WebUtility.inputSQLSanitizer(request.getParameter("email")); + String phone = WebUtility.inputSanitizer(request.getParameter("phone")); + String phoneExtension = WebUtility.inputSanitizer(request.getParameter("phoneextension")); + String countryCode = WebUtility.inputSanitizer(request.getParameter("countrycode")); + + String modelUsageRestriction = WebUtility.inputSanitizer(request.getParameter("modelUsageRestriction")); + if (modelUsageRestriction != null) { + modelUsageRestriction = modelUsageRestriction.trim(); + } + String modelUsageFrequency = WebUtility.inputSanitizer(request.getParameter("modelUsageFrequency")); + if (modelUsageFrequency != null) { + modelUsageFrequency = modelUsageFrequency.trim(); + } + int modelMaxTokens = 0; + String modelMaxTokensStr = WebUtility.inputSanitizer(request.getParameter("modelMaxTokens")); + if (modelMaxTokensStr != null && !(modelMaxTokensStr = modelMaxTokensStr.trim()).isEmpty()) { + // must be a valid integer + try { + modelMaxTokens = Integer.parseInt(modelMaxTokensStr); + } catch (NumberFormatException e) { + classLogger.error("Unexpected error in createNativeUser", e); + ret.put(Constants.ERROR_MESSAGE, "modelMaxTokens must be a valid integer value"); + return WebUtility.getResponse(ret, 400); + } + } + double modelMaxResponseTime = 0.0; + String modelMaxResponseTimeStr = WebUtility.inputSanitizer(request.getParameter("modelMaxResponseTime")); + if (modelMaxResponseTimeStr != null + && !(modelMaxResponseTimeStr = modelMaxResponseTimeStr.trim()).isEmpty()) { + // must be a valid double + try { + modelMaxResponseTime = Double.parseDouble(modelMaxResponseTimeStr); + } catch (NumberFormatException e) { + classLogger.error("Unexpected error in createNativeUser", e); + ret.put(Constants.ERROR_MESSAGE, "modelMaxResponseTime must be a valid double value"); + return WebUtility.getResponse(ret, 400); + } + } + AccessToken newUser = new AccessToken(); + + newUser.setProvider(AuthProvider.NATIVE); + newUser.setId(username); + newUser.setUsername(username); + newUser.setEmail(email); + newUser.setName(name); + newUser.setPhone(phone); + newUser.setPhoneExtension(phoneExtension); + newUser.setCountryCode(countryCode); + // model restriction values + newUser.setModelUsageRestriction(modelUsageRestriction); + newUser.setModelUsageFrequency(modelUsageFrequency); + newUser.setModelMaxTokens(modelMaxTokens); + newUser.setModelMaxResponseTime(modelMaxResponseTime); + + boolean userCreated = SecurityNativeUserUtils.addNativeUser(newUser, password); + if (userCreated) { + ret.put("success", "true"); + ret.put("username", username); + return WebUtility.getResponse(ret, 200); + } else { + ret.put(Constants.ERROR_MESSAGE, "The user name or email aready exists."); + return WebUtility.getResponse(ret, 400); + } + } catch (IllegalArgumentException iae) { + classLogger.error("Unexpected error in createNativeUser", iae); + ret.put(Constants.ERROR_MESSAGE, iae.getMessage()); + return WebUtility.getResponse(ret, 500); + } catch (Exception e) { + classLogger.error("Unexpected error in createNativeUser", e); + ret.put(Constants.ERROR_MESSAGE, "An unexpected error happened. Please try again."); + return WebUtility.getResponse(ret, 500); + } + } + + /** + * Creates an API user credential. email) + * + * @param request + * @return true if the user is created otherwise error. + */ + @POST + @Produces("application/json") + @Path("createAPIUser") + public Response createAPIUser(@Context HttpServletRequest request) { + if (socialData.getLoginsAllowed().get("api_user") == null || !socialData.getLoginsAllowed().get("api_user")) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "API User is not allowed for login"); + return WebUtility.getResponse(ret, 400); + } + + if (Utility.getApplicationAdminOnlyCreateAPIUser()) { + User user = (User) request.getSession().getAttribute(Constants.SESSION_USER); + if (user == null) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "No active session. Please login as an admin"); + return WebUtility.getResponse(ret, 401); + } + if (!SecurityAdminUtils.userIsAdmin(user)) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, + "User is not an admin and does not have access. Please login as an admin"); + return WebUtility.getResponse(ret, 401); + } + } + + String name = WebUtility.inputSQLSanitizer(request.getParameter("name")); + Map oneTimeDetails = SecurityAPIUserUtils.createAPIUser(name); + return WebUtility.getResponse(oneTimeDetails, 200); + } + + ////////////////////////////////////////////////////////////////////// + + /** + * Returns the map of enabled and disabled connection providers. + */ + + @GET + @Produces("application/json") + @Path("/connectionsAllowed/") + public Response connectionsAllowed(@Context HttpServletRequest request) { + return WebUtility.getResponse(socialData.getConnectionsAllowed(), 200); + } + + /** + * Returns the map of enabled and disabled login providers. the FE + */ + + @GET + @Produces("application/json") + @Path("/loginsAllowed/") + public Response loginsAllowed(@Context HttpServletRequest request) { + return WebUtility.getResponse(socialData.getLoginsAllowed(), 200); + } + + /** + * Returns provider property values from social properties for admin users. + * + * @param request inbound HTTP request + * @return login-property map grouped by provider + */ + @GET + @Produces("application/json") + @Path("/loginProperties/") + public Response loginProperties(@Context HttpServletRequest request) { + User user = (User) request.getSession().getAttribute(Constants.SESSION_USER); + if (user == null) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "No user defined to access properties. Please login as an admin"); + return WebUtility.getResponse(ret, 401); + } + if (!SecurityAdminUtils.userIsAdmin(user)) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "User is not an admin and does not have access. Please login as an admin"); + return WebUtility.getResponse(ret, 401); + } + + // you have access - lets send all the info + + Map> loginApps = new TreeMap<>(); + + Set propSet = socialData.stringPropertyNames(); + for (String prop : propSet) { + if (!prop.contains("_")) { + // bad format + // ignore + continue; + } + String[] split = prop.toString().split("_", 2); + String type = split[0]; + String type_key = split[1]; + + if (!loginApps.containsKey(type)) { + loginApps.put(type, new TreeMap()); + } + + loginApps.get(type).put(type_key, socialData.getProperty(prop)); + } + + return WebUtility.getResponse(loginApps, 200); + } + + /** + * Updates social properties for one provider. + * + * @param provider provider key + * @param form form payload containing serialized modifications + * @param request inbound HTTP request + * @return operation result + */ + @POST + @Produces("application/json") + @Path("/modifyLoginProperties/{provider}") + public synchronized Response modifyLoginProperties(@PathParam("provider") String provider, + MultivaluedMap form, @Context HttpServletRequest request) { + + provider = WebUtility.inputSanitizer(provider); + + User user = (User) request.getSession().getAttribute(Constants.SESSION_USER); + if (user == null) { + return WebUtility.getResponse("No user defined to access properties. Please login as an admin", 400); + } + if (!SecurityAdminUtils.userIsAdmin(user)) { + return WebUtility.getResponse("User is not an admin and does not have access. Please login as an admin", + 400); + } + + Gson gson = new Gson(); + Map mods = gson.fromJson(form.getFirst("modifications"), new TypeToken>() { + }.getType()); + Map sanitizedMods = new HashMap<>(); + + for (String key : mods.keySet()) { + sanitizedMods.put(WebUtility.inputSanitizer(key), WebUtility.inputSanitizer(mods.get(key))); + } + + try { + socialData.updateSocialProperties(provider, sanitizedMods); + } catch (Exception e) { + classLogger.error("Unexpected error in modifyLoginProperties", e); + Map errorRet = new HashMap<>(); + errorRet.put(Constants.ERROR_MESSAGE, e.getMessage()); + return WebUtility.getResponse(errorRet, 500); + } + + return WebUtility.getResponse(true, 200); + } + + /** + * Replaces all social properties content. + * + * @param request inbound HTTP request + * @return operation result + */ + @POST + @Produces("application/json") + @Path("/modifyAllLoginProperties") + public synchronized Response modifyAllLoginProperties(@Context HttpServletRequest request) { + User user = (User) request.getSession().getAttribute(Constants.SESSION_USER); + if (user == null) { + return WebUtility.getResponse("No user defined to access properties. Please login as an admin", 400); + } + if (!SecurityAdminUtils.userIsAdmin(user)) { + return WebUtility.getResponse("User is not an admin and does not have access. Please login as an admin", + 400); + } + + String newSocialProperties = request.getParameter("socialProperties"); + try { + socialData.updateAllProperties(newSocialProperties); + } catch (Exception e) { + classLogger.error("Unexpected error in modifyAllLoginProperties", e); + Map errorRet = new HashMap<>(); + errorRet.put(Constants.ERROR_MESSAGE, e.getMessage()); + return WebUtility.getResponse(errorRet, 500); + } + + return WebUtility.getResponse(true, 200); + } + + /** + * Returns the full raw social-properties file content for admin users. + * + * @param request inbound HTTP request + * @return social-properties content response + */ + @GET + @Produces("application/json") + @Path("/getAllLoginProperties") + public synchronized Response getAllLoginProperties(@Context HttpServletRequest request) { + User user = (User) request.getSession().getAttribute(Constants.SESSION_USER); + if (user == null) { + return WebUtility.getResponse("No user defined to access properties. Please login as an admin", 400); + } + if (!SecurityAdminUtils.userIsAdmin(user)) { + return WebUtility.getResponse("User is not an admin and does not have access. Please login as an admin", + 400); + } + + try { + String fileContent = socialData.getFileContents(); + Map retMap = new HashMap<>(); + retMap.put("content", fileContent); + return WebUtility.getResponse(retMap, 200); + } catch (Exception e) { + classLogger.error("Unexpected error in getAllLoginProperties", e); + Map errorRet = new HashMap<>(); + errorRet.put(Constants.ERROR_MESSAGE, e.getMessage()); + return WebUtility.getResponse(errorRet, 500); + } + } + + /** + * Redirects a successful login to the main app page or a stored custom + * redirect. + * + * @param request inbound HTTP request + * @param response outbound HTTP response + */ + private void setMainPageRedirect(@Context HttpServletRequest request, @Context HttpServletResponse response) { + String customRedirect = WebUtility.cleanHttpResponse(request.getParameter("redirect")); + if (customRedirect == null || customRedirect.isEmpty()) { + customRedirect = (String) request.getSession().getAttribute(CUSTOM_REDIRECT_SESSION_KEY); + // also remove the attribute so additional logins dont do the redirect as well + request.getSession().removeAttribute(CUSTOM_REDIRECT_SESSION_KEY); + } + setMainPageRedirect(request, response, customRedirect); + } + + /** + * Redirects a successful login to the requested destination. + * + * @param request inbound HTTP request + * @param response outbound HTTP response + * @param customRedirect explicit redirect URL when provided + */ + private void setMainPageRedirect(@Context HttpServletRequest request, @Context HttpServletResponse response, + String customRedirect) { + // see if we have a location to redirect the user + // if so, we will send them back to that URL + // otherwise, we send them back to the FE + HttpSession session = request.getSession(); + String contextPath = request.getContextPath(); + + boolean useCustom = customRedirect != null && !customRedirect.isEmpty(); + boolean endpoint = session.getAttribute(Constants.ENDPOINT_REDIRECT_KEY) != null; + response.setStatus(302); + try { + boolean secureRequest = "https".equalsIgnoreCase(WebUtility.getProtocol(request)); + // add the cookie to the header directly + // to allow for cross site login when embedded as iframe + String setCookieString = DBLoader.getSessionIdKey() + "=" + session.getId() + "; Path=" + contextPath + + "; HttpOnly" + + ((ClusterUtil.IS_CLUSTER || secureRequest) + ? ("; Secure; SameSite=" + Utility.getSameSiteCookieValue()) + : ""); + response.addHeader("Set-Cookie", setCookieString); + if (useCustom) { + response.addHeader("redirect", customRedirect); + String encodedCustomRedirect = Encode.forHtml(customRedirect); + response.sendError(302, "Need to redirect to " + encodedCustomRedirect); + } else if (endpoint) { + String redirectUrl = session.getAttribute(Constants.ENDPOINT_REDIRECT_KEY) + ""; + response.addHeader("redirect", redirectUrl); + response.sendError(302, "Need to redirect to " + redirectUrl); + } else { + response.sendRedirect(socialData.getProperty("redirect")); + } + } catch (IOException e) { + classLogger.error("Unexpected error in setMainPageRedirect", e); + } + } + + ////////////////////////////////////////////////////////////////////// + + /** + * Returns servlet-container principal details for the current request. + * + * @param request inbound HTTP request + * @param response outbound HTTP response + * @return principal and group metadata payload + */ + @GET + @Produces("application/json") + @Path("/whoami") + public Response show(@Context HttpServletRequest request, @Context HttpServletResponse response) { + Principal principal = request.getUserPrincipal(); + Map output = new HashMap<>(); + if (principal != null) { + output.put("name", principal.getName()); + if (principal instanceof WindowsPrincipal) { + WindowsPrincipal windowsPrincipal = (WindowsPrincipal) principal; + List> gropus = new ArrayList<>(); + for (waffle.windows.auth.WindowsAccount account : windowsPrincipal.getGroups().values()) { + Map m = new HashMap<>(); + m.put("name", account.getName()); + m.put("domain", account.getDomain()); + m.put("fqn", account.getFqn()); + m.put("sid", account.getSidString()); + gropus.add(m); + } + output.put("groups", gropus); + } + } else { + HttpSession session = request.getSession(false); + if (session != null) { + User user = (User) session.getAttribute(Constants.SESSION_USER); + if (user != null) { + AccessToken token = user.getAccessToken(user.getPrimaryLogin()); + output.put("name", token.getId()); + output.put("warning", "null principal - grab from user"); + } + } + if (output.isEmpty()) { + output.put(Constants.ERROR_MESSAGE, "null principal"); + } + } + return WebUtility.getResponse(output, 200); + } + +} From 27e86fa45837b5a45081782edfe3d9531ecb0e7c Mon Sep 17 00:00:00 2001 From: Subhadeepghosh1 Date: Mon, 6 Jul 2026 14:21:41 +0530 Subject: [PATCH 17/20] fix: updated the loginGeneric to handle the login and connection flow --- .../web/services/local/UserResource.java | 55 +++++++++++++++++-- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/src/prerna/semoss/web/services/local/UserResource.java b/src/prerna/semoss/web/services/local/UserResource.java index fbf7b8214..6bd4a1948 100644 --- a/src/prerna/semoss/web/services/local/UserResource.java +++ b/src/prerna/semoss/web/services/local/UserResource.java @@ -517,6 +517,17 @@ private User refreshSessionUser(HttpServletRequest request, HttpSession session) private boolean hasAccessToken(User user, AuthProvider provider) { return user != null && user.getAccessToken(provider) != null; } + + /** + * Checks whether a user has a resource access token for the requested provider. + * + * @param user user to inspect + * @param provider authentication provider + * @return {@code true} when a token exists + */ + private boolean hasResourceAccessToken(User user, AuthProvider provider) { + return user != null && user.getResourceAccessToken(provider) != null; + } /** * Encodes the request query string for safe OAuth parsing. @@ -1151,6 +1162,16 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS return loginGeneric("twitter", request, response); } + /** + * Checks whether the current session already has an authenticated login user. + * + * @param user session user to inspect + * @return {@code true} when the session user exists and has at least one login + */ + private boolean hasLoggedInUser(User user) { + return user != null && user.getLogins() != null && !user.getLogins().isEmpty(); + } + /** * Handles OAuth login callback flow for a generic provider. */ @@ -1160,9 +1181,12 @@ public Response loginTwitter(@Context HttpServletRequest request, @Context HttpS public Response loginGeneric(@PathParam("provider") String provider, @Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { provider = WebUtility.inputSanitizer(provider); - if (socialData.getLoginsAllowed().get(provider) == null || !socialData.getLoginsAllowed().get(provider)) { - Map ret = new HashMap<>(); - ret.put(Constants.ERROR_MESSAGE, provider + " login is not allowed"); + boolean isProviderLoginAllowed = socialData.getLoginsAllowed().getOrDefault(provider.toLowerCase(), false); + boolean isProviderConnectorAllowed = socialData.getConnectionsAllowed().getOrDefault(provider.toLowerCase(), + false); + if (!isProviderLoginAllowed && !isProviderConnectorAllowed) { + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, "Login/Connect with " + provider + " is not allowed"); return WebUtility.getResponse(ret, 400); } @@ -1180,9 +1204,21 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht HttpSession session = initializeOAuthLoginSession(request); User userObj = getSessionUser(session); + boolean useLoginFlow = isProviderLoginAllowed; + boolean useConnectorFlow = !useLoginFlow && isProviderConnectorAllowed; + if (useConnectorFlow && !hasLoggedInUser(userObj)) { + // A logged-in user is required to connect an external account, so if the + // session user is null or has no logins, return an error. + Map ret = new HashMap<>(); + ret.put(Constants.ERROR_MESSAGE, + "Log in with a native or other social account before connecting " + provider); + return WebUtility.getResponse(ret, 401); + } + boolean needsLogin = useLoginFlow && !hasAccessToken(userObj, providerEnum); + boolean needsConnector = useConnectorFlow && !hasResourceAccessToken(userObj, providerEnum); String queryString = getEncodedQueryString(request); if (hasOAuthCode(queryString)) { - if (!hasAccessToken(userObj, providerEnum)) { + if (needsLogin || needsConnector) { String[] outputs = HttpHelperUtility.getCodes(queryString); // oauth code should match [ -~]+ (1 or more ascii) @@ -1212,7 +1248,14 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht // fill user groups filler.fillUserGroups(accessToken, prefix); - addAccessToken(accessToken, request, autoAdd); + if (needsLogin) { + // add the access token to the session user (creating a new user if needed) + addAccessToken(accessToken, request, autoAdd); + } else if (needsConnector) { + // add the access token to the session user (no auto-add since the user must + // already exist) + addResourceAccessToken(accessToken, request); + } classLogger.debug("Access Token is.. {}", accessToken.getAccess_token()); } @@ -1220,7 +1263,7 @@ public Response loginGeneric(@PathParam("provider") String provider, @Context Ht } userObj = refreshSessionUser(request, session); - if (!hasAccessToken(userObj, providerEnum)) { + if (needsLogin || needsConnector) { // not authenticated response.setStatus(302); response.sendRedirect(buildProviderAuthorizeRedirect(filler, prefix, session)); From aff608d4d097d7f3edb875ecae403efbf409fe7c Mon Sep 17 00:00:00 2001 From: Maher Khalil Date: Sat, 11 Jul 2026 22:38:08 -0400 Subject: [PATCH 18/20] feat: adding endpoints to view engines user does not have access to (#376) --- .../AdminEngineAuthorizationResource.java | 39 ++++++ .../AdminProjectAuthorizationResource.java | 119 +++++------------- .../auth/ProjectAuthorizationResource.java | 73 ----------- 3 files changed, 72 insertions(+), 159 deletions(-) diff --git a/src/prerna/semoss/web/services/local/auth/AdminEngineAuthorizationResource.java b/src/prerna/semoss/web/services/local/auth/AdminEngineAuthorizationResource.java index e82124d29..c649c5edf 100644 --- a/src/prerna/semoss/web/services/local/auth/AdminEngineAuthorizationResource.java +++ b/src/prerna/semoss/web/services/local/auth/AdminEngineAuthorizationResource.java @@ -289,6 +289,45 @@ public Response getAllUserEngines(@Context HttpServletRequest request, Multivalu return WebUtility.getResponse(adminUtils.getAllUserEngines(userId, engineTypes), 200); } + @POST + @Path("/getUserEnginesNoCredentials") + @Produces("application/json") + public Response getUserEnginesNoCredentials(@Context HttpServletRequest request, + MultivaluedMap form) { + SecurityAdminUtils adminUtils = null; + User user = null; + String userId = WebUtility.inputSQLSanitizer(form.getFirst("userId")); + String searchTerm = WebUtility.inputSQLSanitizer(form.getFirst("searchTerm")); + List engineTypes = null; + if (WebUtility.inputSQLSanitizer(form.getFirst("engineTypes")) != null) { + engineTypes = new Gson().fromJson(form.getFirst("engineTypes"), List.class); + engineTypes = WebUtility.inputSanitizer(engineTypes); + } + long limit = 0; + long offset = 0; + if (form.getFirst("limit") != null) { + limit = Long.parseLong(form.getFirst("limit")); + } + if (form.getFirst("offset") != null) { + offset = Long.parseLong(form.getFirst("offset")); + } + try { + user = ResourceUtility.getUser(request); + adminUtils = performAdminCheck(request, user); + } catch (IllegalAccessException e) { + classLogger.warn( + "User is trying to pull the engines that user {} does not have access to when not an admin", + userId); + classLogger.error("Failed to list the engines that user {} does not have access to", userId, e); + Map errorMap = new HashMap(); + errorMap.put(Constants.ERROR_MESSAGE, e.getMessage()); + return WebUtility.getResponse(errorMap, 401); + } + + return WebUtility.getResponse( + adminUtils.getUserEnginesNoCredentials(userId, engineTypes, searchTerm, limit, offset), 200); + } + @POST @Path("/grantAllEngines") @Produces("application/json") diff --git a/src/prerna/semoss/web/services/local/auth/AdminProjectAuthorizationResource.java b/src/prerna/semoss/web/services/local/auth/AdminProjectAuthorizationResource.java index 7901c3410..712f1430f 100644 --- a/src/prerna/semoss/web/services/local/auth/AdminProjectAuthorizationResource.java +++ b/src/prerna/semoss/web/services/local/auth/AdminProjectAuthorizationResource.java @@ -30,7 +30,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Properties; import java.util.stream.Collectors; import javax.annotation.security.PermitAll; @@ -54,23 +53,18 @@ import prerna.auth.AuthProvider; import prerna.auth.User; import prerna.auth.utils.SecurityAdminUtils; -import prerna.auth.utils.SecurityProjectUtils; import prerna.auth.utils.SecurityQueryUtils; import prerna.auth.utils.SecurityUpdateUtils; import prerna.auth.utils.reactors.admin.AdminMyProjectsReactor; -import prerna.cluster.util.ClusterUtil; import prerna.graph.utility.MsGraphUtility; import prerna.om.Insight; -import prerna.project.api.IProject; import prerna.sablecc2.om.GenRowStruct; import prerna.sablecc2.om.PixelDataType; import prerna.sablecc2.om.ReactorKeysEnum; import prerna.sablecc2.om.nounmeta.NounMetadata; import prerna.semoss.web.services.local.ResourceUtility; import prerna.util.Constants; -import prerna.util.Settings; import prerna.util.SocialPropertiesUtil; -import prerna.util.Utility; import prerna.web.services.util.WebUtility; @Path("/auth/admin/project") @@ -275,6 +269,39 @@ public Response getAllUserProjects(@Context HttpServletRequest request, Multival return WebUtility.getResponse(adminUtils.getAllUserProjects(userId), 200); } + @POST + @Path("/getUserProjectsNoCredentials") + @Produces("application/json") + public Response getUserProjectsNoCredentials(@Context HttpServletRequest request, + MultivaluedMap form) { + SecurityAdminUtils adminUtils = null; + User user = null; + String userId = WebUtility.inputSQLSanitizer(form.getFirst("userId")); + String searchTerm = WebUtility.inputSQLSanitizer(form.getFirst("searchTerm")); + long limit = 0; + long offset = 0; + if (form.getFirst("limit") != null) { + limit = Long.parseLong(form.getFirst("limit")); + } + if (form.getFirst("offset") != null) { + offset = Long.parseLong(form.getFirst("offset")); + } + try { + user = ResourceUtility.getUser(request); + adminUtils = performAdminCheck(request, user); + } catch (IllegalAccessException e) { + classLogger.warn( + "User is trying to pull the projects that user {} does not have access to when not an admin", + userId); + classLogger.error("Failed to list the projects that user {} does not have access to", userId, e); + Map errorMap = new HashMap(); + errorMap.put(Constants.ERROR_MESSAGE, e.getMessage()); + return WebUtility.getResponse(errorMap, 401); + } + + return WebUtility.getResponse(adminUtils.getUserProjectsNoCredentials(userId, searchTerm, limit, offset), 200); + } + @POST @Path("/grantAllProjects") @Produces("application/json") @@ -1027,84 +1054,4 @@ public Response removeProjectUserPermissions(@Context HttpServletRequest request return WebUtility.getResponse(ret, 200); } - @POST - @Produces("application/json") - @Path("setProjectPortal") - public Response setProjectPortal(@Context HttpServletRequest request, MultivaluedMap form) { - SecurityAdminUtils adminUtils = null; - User user = null; - - String projectId = WebUtility.inputSQLSanitizer(form.getFirst("projectId")); - boolean hasPortal = Boolean.parseBoolean(form.getFirst("hasPortal")); - String portalName = WebUtility.inputSQLSanitizer(form.getFirst("portalName")); - String logPortal = hasPortal ? " enable portal " : " disable portal"; - - try { - user = ResourceUtility.getUser(request); - adminUtils = performAdminCheck(request, user); - } catch (IllegalAccessException e) { - classLogger.warn("User is trying to {} for project {}", logPortal, projectId); - classLogger.error("Failed to update project portal.", e); - Map errorMap = new HashMap(); - errorMap.put(Constants.ERROR_MESSAGE, e.getMessage()); - return WebUtility.getResponse(errorMap, 401); - } - - try { - adminUtils.setProjectPortal(user, projectId, hasPortal, portalName); - } catch (Exception e) { - classLogger.error("Failed to update project portal.", e); - Map errorRet = new HashMap(); - errorRet.put(Constants.ERROR_MESSAGE, "An unexpected error happened. Please try again."); - return WebUtility.getResponse(errorRet, 500); - } - - IProject project = Utility.getProject(projectId); - try { - SecurityProjectUtils.setProjectPortal(user, projectId, hasPortal, portalName); - project.setHasPortal(hasPortal); - } catch (IllegalAccessException e) { - classLogger.warn("User is trying to {} for project {}", logPortal, projectId); - classLogger.error("Failed to update project portal.", e); - Map errorRet = new HashMap(); - errorRet.put(Constants.ERROR_MESSAGE, e.getMessage()); - return WebUtility.getResponse(errorRet, 400); - } catch (Exception e) { - classLogger.error("Failed to update project portal.", e); - Map errorRet = new HashMap(); - errorRet.put(Constants.ERROR_MESSAGE, "An unexpected error happened. Please try again."); - return WebUtility.getResponse(errorRet, 500); - } - - try { - String projectSmss = project.getSmssFilePath(); - Map mods = new HashMap<>(); - mods.put(Settings.PUBLIC_HOME_ENABLE, hasPortal + ""); - Properties props = Utility.loadProperties(projectSmss); - if (props.get(Settings.PUBLIC_HOME_ENABLE) == null) { - classLogger.info("Updating project smss to include public home property to {} for project {}", - logPortal, Utility.cleanLogString(projectId)); - Utility.addKeysAtLocationIntoPropertiesFile(projectSmss, Constants.CONNECTION_URL, mods); - } else { - classLogger.info("Modifying project smss to {} for project {}", logPortal, - Utility.cleanLogString(projectId)); - Utility.changePropertiesFileValue(projectSmss, Settings.PUBLIC_HOME_ENABLE, hasPortal + ""); - } - - // reload and set the prop again - Properties newSmssProp = Utility.loadProperties(projectSmss); - project.setSmssProp(newSmssProp); - - // push to cloud - ClusterUtil.pushProjectSmss(projectId); - } catch (Exception e) { - // ignore - } - - // log the operation - classLogger.info("User is trying to {} for project {}", logPortal, projectId); - - return WebUtility.getResponse(true, 200); - } - } diff --git a/src/prerna/semoss/web/services/local/auth/ProjectAuthorizationResource.java b/src/prerna/semoss/web/services/local/auth/ProjectAuthorizationResource.java index 8927bae54..3a3c12600 100644 --- a/src/prerna/semoss/web/services/local/auth/ProjectAuthorizationResource.java +++ b/src/prerna/semoss/web/services/local/auth/ProjectAuthorizationResource.java @@ -30,7 +30,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Properties; import java.util.stream.Collectors; import javax.annotation.security.PermitAll; @@ -58,10 +57,8 @@ import prerna.auth.utils.SecurityProjectUtils; import prerna.auth.utils.SecurityQueryUtils; import prerna.auth.utils.SecurityUpdateUtils; -import prerna.cluster.util.ClusterUtil; import prerna.graph.utility.MsGraphUtility; import prerna.om.Insight; -import prerna.project.api.IProject; import prerna.reactor.project.MyProjectsReactor; import prerna.sablecc2.om.GenRowStruct; import prerna.sablecc2.om.PixelDataType; @@ -69,9 +66,7 @@ import prerna.sablecc2.om.nounmeta.NounMetadata; import prerna.semoss.web.services.local.ResourceUtility; import prerna.util.Constants; -import prerna.util.Settings; import prerna.util.SocialPropertiesUtil; -import prerna.util.Utility; import prerna.web.services.util.WebUtility; @Path("/auth/project") @@ -1287,72 +1282,4 @@ public Response removeProjectUserPermissions(@Context HttpServletRequest request return WebUtility.getResponse(ret, 200); } - @POST - @Produces("application/json") - @Path("setProjectPortal") - public Response setProjectPortal(@Context HttpServletRequest request, MultivaluedMap form) { - User user = null; - try { - user = ResourceUtility.getUser(request); - } catch (IllegalAccessException e) { - classLogger.error("Invalid user session trying to access authorization resources", e); - Map errorMap = new HashMap(); - errorMap.put(Constants.ERROR_MESSAGE, "User session is invalid"); - return WebUtility.getResponse(errorMap, 401); - } - - String projectId = WebUtility.inputSanitizer(form.getFirst("projectId")); - boolean hasPortal = Boolean.parseBoolean(form.getFirst("hasPortal")); - String portalName = WebUtility.inputSanitizer(form.getFirst("portalName")); - String logPortal = hasPortal ? " enable portal " : " disable portal"; - - IProject project = Utility.getProject(projectId); - try { - SecurityProjectUtils.setProjectPortal(user, projectId, hasPortal, portalName); - project.setHasPortal(hasPortal); - } catch (IllegalAccessException e) { - classLogger.warn("User is trying to {} for project {}", logPortal, projectId); - classLogger.error("Failed to update portal settings for project {} because access validation failed.", - projectId, e); - Map errorRet = new HashMap(); - errorRet.put(Constants.ERROR_MESSAGE, e.getMessage()); - return WebUtility.getResponse(errorRet, 400); - } catch (Exception e) { - classLogger.error("Failed to update portal settings for project {}.", projectId, e); - Map errorRet = new HashMap(); - errorRet.put(Constants.ERROR_MESSAGE, "An unexpected error happened. Please try again."); - return WebUtility.getResponse(errorRet, 500); - } - - try { - String projectSmss = project.getSmssFilePath(); - Map mods = new HashMap<>(); - mods.put(Settings.PUBLIC_HOME_ENABLE, hasPortal + ""); - Properties props = Utility.loadProperties(projectSmss); - if (props.get(Settings.PUBLIC_HOME_ENABLE) == null) { - classLogger.info("Updating project smss to include public home property to {} for project {}", - logPortal, Utility.cleanLogString(projectId)); - Utility.addKeysAtLocationIntoPropertiesFile(projectSmss, Constants.CONNECTION_URL, mods); - } else { - classLogger.info("Modifying project smss to {} for project {}", logPortal, - Utility.cleanLogString(projectId)); - Utility.changePropertiesFileValue(projectSmss, Settings.PUBLIC_HOME_ENABLE, hasPortal + ""); - } - - // reload and set the prop again - Properties newSmssProp = Utility.loadProperties(projectSmss); - project.setSmssProp(newSmssProp); - - // push to cloud - ClusterUtil.pushProjectSmss(projectId); - } catch (Exception e) { - // ignore - } - - // log the operation - classLogger.info("User is trying to {} for project {}", logPortal, projectId); - - return WebUtility.getResponse(true, 200); - } - } From 41e8273a496c30e05c3587d673e32170e325dab6 Mon Sep 17 00:00:00 2001 From: Maher Khalil Date: Sat, 11 Jul 2026 23:00:55 -0400 Subject: [PATCH 19/20] chore: removing deprecated and unused endpoint (#377) --- .../auth/AdminUserAuthorizationResource.java | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/src/prerna/semoss/web/services/local/auth/AdminUserAuthorizationResource.java b/src/prerna/semoss/web/services/local/auth/AdminUserAuthorizationResource.java index fd73e16cf..1152387b6 100644 --- a/src/prerna/semoss/web/services/local/auth/AdminUserAuthorizationResource.java +++ b/src/prerna/semoss/web/services/local/auth/AdminUserAuthorizationResource.java @@ -377,34 +377,6 @@ public Response deleteUser(@Context HttpServletRequest request, MultivaluedMap errorMap = new HashMap(); - errorMap.put(Constants.ERROR_MESSAGE, e.getMessage()); - return WebUtility.getResponse(errorMap, 401); - } - - List> ret = adminUtils.getAllUsers(null, -1, -1); - return WebUtility.getResponse(ret, 200); - } - @GET @Path("/getAllUsers") @Produces("application/json") From 4e83df34bde8b2e199e876beb13865d608f9e69e Mon Sep 17 00:00:00 2001 From: Maher Khalil Date: Sun, 12 Jul 2026 00:44:30 -0400 Subject: [PATCH 20/20] feat: adding limit, offset, project type, changing post to get for endpoints (#378) --- .../AdminEngineAuthorizationResource.java | 46 +++++++------------ .../AdminProjectAuthorizationResource.java | 39 ++++++++-------- 2 files changed, 36 insertions(+), 49 deletions(-) diff --git a/src/prerna/semoss/web/services/local/auth/AdminEngineAuthorizationResource.java b/src/prerna/semoss/web/services/local/auth/AdminEngineAuthorizationResource.java index c649c5edf..3d276fca8 100644 --- a/src/prerna/semoss/web/services/local/auth/AdminEngineAuthorizationResource.java +++ b/src/prerna/semoss/web/services/local/auth/AdminEngineAuthorizationResource.java @@ -263,18 +263,17 @@ public Response getEnginesPOST(@Context HttpServletRequest request) { return WebUtility.getResponse(outputNoun.getValue(), 200); } - @POST + @GET @Path("/getAllUserEngines") @Produces("application/json") - public Response getAllUserEngines(@Context HttpServletRequest request, MultivaluedMap form) { + public Response getAllUserEngines(@Context HttpServletRequest request, @QueryParam("userId") String userId, + @QueryParam("engineTypes") List engineTypes, @QueryParam("searchTerm") String searchTerm, + @QueryParam("limit") long limit, @QueryParam("offset") long offset) { + userId = WebUtility.inputSQLSanitizer(userId); + searchTerm = WebUtility.inputSQLSanitizer(searchTerm); + engineTypes = WebUtility.inputSanitizer(engineTypes); SecurityAdminUtils adminUtils = null; User user = null; - String userId = WebUtility.inputSQLSanitizer(form.getFirst("userId")); - List engineTypes = null; - if (WebUtility.inputSQLSanitizer(form.getFirst("engineTypes")) != null) { - engineTypes = new Gson().fromJson(form.getFirst("engineTypes"), List.class); - engineTypes = WebUtility.inputSanitizer(engineTypes); - } try { user = ResourceUtility.getUser(request); adminUtils = performAdminCheck(request, user); @@ -286,38 +285,27 @@ public Response getAllUserEngines(@Context HttpServletRequest request, Multivalu return WebUtility.getResponse(errorMap, 401); } - return WebUtility.getResponse(adminUtils.getAllUserEngines(userId, engineTypes), 200); + return WebUtility.getResponse(adminUtils.getAllUserEngines(userId, engineTypes, searchTerm, limit, offset), + 200); } - @POST + @GET @Path("/getUserEnginesNoCredentials") @Produces("application/json") public Response getUserEnginesNoCredentials(@Context HttpServletRequest request, - MultivaluedMap form) { + @QueryParam("userId") String userId, @QueryParam("engineTypes") List engineTypes, + @QueryParam("searchTerm") String searchTerm, @QueryParam("limit") long limit, + @QueryParam("offset") long offset) { + userId = WebUtility.inputSQLSanitizer(userId); + searchTerm = WebUtility.inputSQLSanitizer(searchTerm); + engineTypes = WebUtility.inputSanitizer(engineTypes); SecurityAdminUtils adminUtils = null; User user = null; - String userId = WebUtility.inputSQLSanitizer(form.getFirst("userId")); - String searchTerm = WebUtility.inputSQLSanitizer(form.getFirst("searchTerm")); - List engineTypes = null; - if (WebUtility.inputSQLSanitizer(form.getFirst("engineTypes")) != null) { - engineTypes = new Gson().fromJson(form.getFirst("engineTypes"), List.class); - engineTypes = WebUtility.inputSanitizer(engineTypes); - } - long limit = 0; - long offset = 0; - if (form.getFirst("limit") != null) { - limit = Long.parseLong(form.getFirst("limit")); - } - if (form.getFirst("offset") != null) { - offset = Long.parseLong(form.getFirst("offset")); - } try { user = ResourceUtility.getUser(request); adminUtils = performAdminCheck(request, user); } catch (IllegalAccessException e) { - classLogger.warn( - "User is trying to pull the engines that user {} does not have access to when not an admin", - userId); + classLogger.warn("Non-admin user tried to list the engines that user {} does not have access to", userId); classLogger.error("Failed to list the engines that user {} does not have access to", userId, e); Map errorMap = new HashMap(); errorMap.put(Constants.ERROR_MESSAGE, e.getMessage()); diff --git a/src/prerna/semoss/web/services/local/auth/AdminProjectAuthorizationResource.java b/src/prerna/semoss/web/services/local/auth/AdminProjectAuthorizationResource.java index 712f1430f..21bf937b9 100644 --- a/src/prerna/semoss/web/services/local/auth/AdminProjectAuthorizationResource.java +++ b/src/prerna/semoss/web/services/local/auth/AdminProjectAuthorizationResource.java @@ -247,13 +247,17 @@ public Response getProjectsPOST(@Context HttpServletRequest request) { return WebUtility.getResponse(outputNoun.getValue(), 200); } - @POST + @GET @Path("/getAllUserProjects") @Produces("application/json") - public Response getAllUserProjects(@Context HttpServletRequest request, MultivaluedMap form) { + public Response getAllUserProjects(@Context HttpServletRequest request, @QueryParam("userId") String userId, + @QueryParam("projectTypes") List projectTypes, @QueryParam("searchTerm") String searchTerm, + @QueryParam("limit") long limit, @QueryParam("offset") long offset) { + userId = WebUtility.inputSQLSanitizer(userId); + searchTerm = WebUtility.inputSQLSanitizer(searchTerm); + projectTypes = WebUtility.inputSanitizer(projectTypes); SecurityAdminUtils adminUtils = null; User user = null; - String userId = WebUtility.inputSQLSanitizer(form.getFirst("userId")); try { user = ResourceUtility.getUser(request); adminUtils = performAdminCheck(request, user); @@ -266,40 +270,35 @@ public Response getAllUserProjects(@Context HttpServletRequest request, Multival return WebUtility.getResponse(errorMap, 401); } - return WebUtility.getResponse(adminUtils.getAllUserProjects(userId), 200); + return WebUtility.getResponse(adminUtils.getAllUserProjects(userId, projectTypes, searchTerm, limit, offset), + 200); } - @POST + @GET @Path("/getUserProjectsNoCredentials") @Produces("application/json") public Response getUserProjectsNoCredentials(@Context HttpServletRequest request, - MultivaluedMap form) { + @QueryParam("userId") String userId, @QueryParam("projectTypes") List projectTypes, + @QueryParam("searchTerm") String searchTerm, @QueryParam("limit") long limit, + @QueryParam("offset") long offset) { + userId = WebUtility.inputSQLSanitizer(userId); + searchTerm = WebUtility.inputSQLSanitizer(searchTerm); + projectTypes = WebUtility.inputSanitizer(projectTypes); SecurityAdminUtils adminUtils = null; User user = null; - String userId = WebUtility.inputSQLSanitizer(form.getFirst("userId")); - String searchTerm = WebUtility.inputSQLSanitizer(form.getFirst("searchTerm")); - long limit = 0; - long offset = 0; - if (form.getFirst("limit") != null) { - limit = Long.parseLong(form.getFirst("limit")); - } - if (form.getFirst("offset") != null) { - offset = Long.parseLong(form.getFirst("offset")); - } try { user = ResourceUtility.getUser(request); adminUtils = performAdminCheck(request, user); } catch (IllegalAccessException e) { - classLogger.warn( - "User is trying to pull the projects that user {} does not have access to when not an admin", - userId); + classLogger.warn("Non-admin user tried to list the projects that user {} does not have access to", userId); classLogger.error("Failed to list the projects that user {} does not have access to", userId, e); Map errorMap = new HashMap(); errorMap.put(Constants.ERROR_MESSAGE, e.getMessage()); return WebUtility.getResponse(errorMap, 401); } - return WebUtility.getResponse(adminUtils.getUserProjectsNoCredentials(userId, searchTerm, limit, offset), 200); + return WebUtility.getResponse( + adminUtils.getUserProjectsNoCredentials(userId, projectTypes, searchTerm, limit, offset), 200); } @POST