Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
85ab5ab
feat(DecoupleOauthResource): Code changes to decouple oauth resource …
Subhadeepghosh1 Nov 11, 2025
487485f
fix: updated logout logic to handle resource and login providers logout
Subhadeepghosh1 Nov 12, 2025
07af2bd
fix: updated checks for logout
Subhadeepghosh1 Nov 12, 2025
30ae2c5
fix: added logic for token removal on logout
Subhadeepghosh1 Nov 13, 2025
cedceed
fix: Added resource connections and details
Subhadeepghosh1 Nov 14, 2025
3562472
fix: used setMainPageRedirect for all logins types and update use of …
Subhadeepghosh1 Nov 16, 2025
11d3ea4
fix: Updated checks and use getAccessToken to fetch tokens
Subhadeepghosh1 Nov 17, 2025
1352969
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Nov 19, 2025
d1fb658
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Nov 24, 2025
55359a8
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Jan 2, 2026
dd1cbba
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Jan 20, 2026
a5a2317
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Jan 27, 2026
56f75fa
fix: Added getAvailableAccessToken logic
Jan 27, 2026
6f773e5
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Feb 3, 2026
1aa346c
fix: update login and logout logic
Feb 5, 2026
0fcddad
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Feb 9, 2026
58c796a
fix: updated code based on pr review comments
Feb 9, 2026
42cc4c5
Update UserResource.java
Subhadeepghosh1 Feb 9, 2026
8933a52
Merge branch 'dev' into decouple-oauth-resource-connections
kunal0137 Feb 12, 2026
497c07b
Updated code as per pr review comments
Subhadeepghosh1 Feb 12, 2026
53fdb0d
fixed method name
Subhadeepghosh1 Feb 17, 2026
cc5cd2b
fix: Added prompt=consent in the google redirect method for refresh t…
Feb 17, 2026
02ecaa9
Properly update needsLogin and needsconnect flags
Subhadeepghosh1 Feb 18, 2026
a8cac29
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Feb 23, 2026
e56587b
Merge branch 'dev' into decouple-oauth-resource-connections
kunal0137 Mar 3, 2026
11cfa85
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Mar 4, 2026
ebd14fe
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Mar 6, 2026
b39635d
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Mar 9, 2026
965846b
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Mar 10, 2026
ac857d3
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Mar 11, 2026
5ed878c
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Mar 17, 2026
214fc63
Merge branch 'dev' into decouple-oauth-resource-connections
snehakumari369 Mar 20, 2026
de5a131
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Mar 23, 2026
a8500e1
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Mar 26, 2026
e6c7b49
Merge branch 'dev' into decouple-oauth-resource-connections
snehakumari369 Apr 1, 2026
2f7c080
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 May 11, 2026
4ebd68d
fix: Removed merge conflicts and code cleanup
May 11, 2026
4756c8d
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 May 12, 2026
2765c96
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Jun 15, 2026
baaf4de
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Jun 17, 2026
fc4c648
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Jun 23, 2026
810981e
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Jul 6, 2026
27e86fa
fix: updated the loginGeneric to handle the login and connection flow
Jul 6, 2026
aff608d
feat: adding endpoints to view engines user does not have access to (…
themaherkhalil Jul 12, 2026
41e8273
chore: removing deprecated and unused endpoint (#377)
themaherkhalil Jul 12, 2026
4e83df3
feat: adding limit, offset, project type, changing post to get for en…
themaherkhalil Jul 12, 2026
98971ea
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Jul 14, 2026
088220e
Merge branch 'dev' into decouple-oauth-resource-connections
Subhadeepghosh1 Jul 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -256,24 +256,28 @@ private static void loadConfig() {
private static Map<String, Object> getConfiguration(@Context HttpServletRequest request, User user) {
HttpSession session = request.getSession();

Map<String, Object> myConfiguration = new HashMap<>();
myConfiguration.putAll(config);
Map<String, Object> 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
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
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(
"Failed to load password requirements; 'passwordRequirements' will be omitted from server config",
Expand All @@ -284,29 +288,32 @@ private static Map<String, Object> 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
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));
myConfiguration.put("userMetaKeys", SecurityUserUtils.getMetakeyOptions(null));
myConfiguration.put("notificationEnabled", Utility.isNotificationDatabaseEnabled());
myConfiguration.put("auditLogEnabled", Utility.isAuditLogsDatabaseEnabled());
clientConfig.put("databaseMetaKeys", SecurityEngineUtils.getMetakeyOptions(null));
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("auditLogEnabled", Utility.isAuditLogsDatabaseEnabled());
// 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
Expand Down
156 changes: 136 additions & 20 deletions src/prerna/semoss/web/services/local/UserResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,34 @@ public Response getAllLogins(@Context HttpServletRequest request) {
Map<String, String> 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<NewCookie> 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<String, String> 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.
Expand Down Expand Up @@ -185,21 +213,33 @@ public Response logout(@PathParam("provider") String provider,
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);
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);
}
}
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());
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());
}
}
}

Expand Down Expand Up @@ -263,6 +303,28 @@ public Response logout(@PathParam("provider") String provider,

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.
Expand Down Expand Up @@ -455,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.
Expand Down Expand Up @@ -1089,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.
*/
Expand All @@ -1098,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<String, Object> 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<String, String> ret = new HashMap<>();
ret.put(Constants.ERROR_MESSAGE, "Login/Connect with " + provider + " is not allowed");
return WebUtility.getResponse(ret, 400);
}

Expand All @@ -1118,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<String, Object> 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)
Expand Down Expand Up @@ -1150,15 +1248,22 @@ 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());
}
}
}

userObj = refreshSessionUser(request, session);
if (!hasAccessToken(userObj, providerEnum)) {
if (needsLogin || needsConnector) {
// not authenticated
response.setStatus(302);
response.sendRedirect(buildProviderAuthorizeRedirect(filler, prefix, session));
Expand Down Expand Up @@ -1638,6 +1743,17 @@ public Response createAPIUser(@Context HttpServletRequest request) {

//////////////////////////////////////////////////////////////////////

/**
* 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
*/
Expand Down
Loading