Skip to content

Commit

Permalink
Merge pull request #2104 from wso2-extensions/audit-logs-imp
Browse files Browse the repository at this point in the history
Add audit logs for oauth application management
  • Loading branch information
piraveena committed Jul 26, 2023
2 parents ac232c9 + e793ab9 commit 67f2e33
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,11 @@ public static class LogConstants {
public static final String SUCCESS = "SUCCESS";
public static final String CLIENT_ID = "client id";
public static final String TENANT_DOMAIN = "tenant domain";
public static final String CREATE_OAUTH_APPLICATION = "CREATE OAUTH APPLICATION";
public static final String UPDATE_OAUTH_APPLICATION = "UPDATE OAUTH APPLICATION";
public static final String DELETE_OAUTH_APPLICATION = "DELETE OAUTH APPLICATION";
public static final String REGENERATE_CLIENT_SECRET = "REGENERATE CLIENT SECRET";
public static final String UPDATE_APP_STATE = "UPDATE APP STATE";
}

/**
Expand Down
5 changes: 5 additions & 0 deletions components/org.wso2.carbon.identity.oauth/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@
<groupId>org.wso2.orbit.org.apache.oltu.oauth2</groupId>
<artifactId>oltu</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.inbound.auth.oauth2</groupId>
<artifactId>org.wso2.carbon.identity.oauth.common</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,27 @@

package org.wso2.carbon.identity.oauth;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONObject;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.identity.application.authentication.framework.exception.UserIdNotFoundException;
import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser;
import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException;
import org.wso2.carbon.identity.application.common.model.User;
import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
import org.wso2.carbon.identity.application.mgt.ApplicationMgtUtil;
import org.wso2.carbon.identity.base.IdentityException;
import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.core.util.IdentityUtil;
import org.wso2.carbon.identity.oauth.cache.AppInfoCache;
import org.wso2.carbon.identity.oauth.cache.OAuthCache;
Expand Down Expand Up @@ -62,6 +71,7 @@
import org.wso2.carbon.identity.oauth2.util.OAuth2Util;
import org.wso2.carbon.identity.oauth2.validators.OAuth2ScopeValidator;
import org.wso2.carbon.user.core.util.UserCoreUtil;
import org.wso2.carbon.utils.AuditLog;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;

import java.util.ArrayList;
Expand All @@ -76,6 +86,9 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.wso2.carbon.identity.application.mgt.ApplicationConstants.LogConstants.TARGET_APPLICATION;
import static org.wso2.carbon.identity.application.mgt.ApplicationConstants.LogConstants.USER;
import static org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils.triggerAuditLogEvent;
import static org.wso2.carbon.identity.oauth.Error.AUTHENTICATED_USER_NOT_FOUND;
import static org.wso2.carbon.identity.oauth.Error.INVALID_OAUTH_CLIENT;
import static org.wso2.carbon.identity.oauth.Error.INVALID_REQUEST;
Expand Down Expand Up @@ -339,6 +352,19 @@ public OAuthConsumerAppDTO registerAndRetrieveOAuthApplicationData(OAuthConsumer
LOG.debug("Oauth Application registration success : " + application.getApplicationName() +
" in tenant domain: " + tenantDomain);
}
if (ApplicationMgtUtil.isLegacyAuditLogsDisabledInAppMgt()) {
Optional<String> initiatorId = getInitiatorId();
if (initiatorId.isPresent()) {
AuditLog.AuditLogBuilder auditLogBuilder = new AuditLog.AuditLogBuilder(
initiatorId.get(), USER,
app.getOauthConsumerKey(), TARGET_APPLICATION,
OAuthConstants.LogConstants.CREATE_OAUTH_APPLICATION)
.data(buildSPData(app));
triggerAuditLogEvent(auditLogBuilder, true);
} else {
LOG.error("Error getting the logged in userId");
}
}
} else {
String message = "No application details in the request. Failed to register OAuth App.";
LOG.debug(message);
Expand All @@ -364,6 +390,65 @@ public OAuthConsumerAppDTO registerAndRetrieveOAuthApplicationData(OAuthConsumer
return OAuthUtil.buildConsumerAppDTO(app);
}


private Optional<AuthenticatedUser> getLoggedInUser(String tenantDomain) {

String tenantAwareLoggedInUsername = CarbonContext.getThreadLocalCarbonContext().getUsername();
return Optional.ofNullable(tenantAwareLoggedInUsername)
.filter(StringUtils::isNotEmpty)
.map(username -> buildAuthenticatedUser(username, tenantDomain));

}

private static Map<String, Object> buildSPData(OAuthAppDO app) {

if (app == null) {
return new HashMap<>();
}
Gson gson = new Gson();
String oauthApp = maskSPData(app);
return gson.fromJson(oauthApp, new TypeToken<Map<String, Object>>() {
}.getType());
}

private static String maskSPData(OAuthAppDO oAuthAppDO) {

if (oAuthAppDO == null) {
return StringUtils.EMPTY;
}
try {
JSONObject oauthAppJSONObject =
new JSONObject(new ObjectMapper().writeValueAsString(oAuthAppDO));
maskClientSecret(oauthAppJSONObject);
maskAppOwnerUsername(oauthAppJSONObject);
return oauthAppJSONObject.toString();
} catch (JsonProcessingException | IdentityException e) {
LOG.error("Error while converting service provider object to json.");
}
return StringUtils.EMPTY;
}

private static void maskAppOwnerUsername(JSONObject oauthAppJSONObject) throws IdentityException {

JSONObject appOwner = oauthAppJSONObject.optJSONObject("appOwner");
if (!LoggerUtils.isLogMaskingEnable || appOwner == null) {
return;
}
String username = (String) appOwner.get("userName");
if (StringUtils.isNotBlank(username)) {
appOwner.put("userName", LoggerUtils.getMaskedContent(username));
}
}

private static void maskClientSecret(JSONObject oauthApp) {

if (oauthApp.get("oauthConsumerSecret") == null) {
return;
}
String secret = oauthApp.get("oauthConsumerSecret").toString();
oauthApp.put("oauthConsumerSecret", LoggerUtils.getMaskedContent(secret));
}

private void validateAudiences(OAuthConsumerAppDTO application) throws IdentityOAuthClientException {

if (application.getAudiences() != null) {
Expand Down Expand Up @@ -545,6 +630,33 @@ public void updateConsumerApplication(OAuthConsumerAppDTO consumerAppDTO) throws
LOG.debug("Oauth Application update success : " + consumerAppDTO.getApplicationName() + " in " +
"tenant domain: " + tenantDomain);
}
if (ApplicationMgtUtil.isLegacyAuditLogsDisabledInAppMgt()) {
Optional<String> initiatorId = getInitiatorId();
if (initiatorId.isPresent()) {
AuditLog.AuditLogBuilder auditLogBuilder = new AuditLog.AuditLogBuilder(
initiatorId.get(), USER, oauthConsumerKey,
TARGET_APPLICATION, OAuthConstants.LogConstants.UPDATE_OAUTH_APPLICATION)
.data(buildSPData(oauthappdo));
triggerAuditLogEvent(auditLogBuilder, true);
} else {
LOG.error("Error getting the logged in userId");
}
}
}

private Optional<String> getInitiatorId() {

String loggedInUserId = CarbonContext.getThreadLocalCarbonContext().getUserId();
if (StringUtils.isNotBlank(loggedInUserId)) {
return Optional.of(loggedInUserId);
} else {
String tenantDomain = getLoggedInTenant();
Optional<AuthenticatedUser> loggedInUser = getLoggedInUser(tenantDomain);
if (loggedInUser.isPresent()) {
return Optional.ofNullable(IdentityUtil.getInitiatorId(loggedInUser.get().getUserName(), tenantDomain));
}
}
return Optional.empty();
}

/**
Expand Down Expand Up @@ -817,6 +929,19 @@ public void updateConsumerAppState(String consumerKey, String newState) throws I
"consumerKey: " + consumerKey);
}

if (ApplicationMgtUtil.isLegacyAuditLogsDisabledInAppMgt()) {
Optional<String> initiatorId = getInitiatorId();
if (initiatorId.isPresent()) {
AuditLog.AuditLogBuilder auditLogBuilder = new AuditLog.AuditLogBuilder(
initiatorId.get(), USER, consumerKey, TARGET_APPLICATION,
OAuthConstants.LogConstants.UPDATE_APP_STATE)
.data(Map.of("state", newState));
triggerAuditLogEvent(auditLogBuilder, true);
} else {
LOG.error("Error getting the logged in userId");
}
}

} catch (InvalidOAuthClientException e) {
String msg = "Error while updating state of OAuth app with consumerKey: " + consumerKey;
throw handleClientError(INVALID_OAUTH_CLIENT, msg, e);
Expand All @@ -836,6 +961,13 @@ public void updateOauthSecretKey(String consumerKey) throws IdentityOAuthAdminEx
updateAndRetrieveOauthSecretKey(consumerKey);
}

private String getLoggedInTenant() {

return Optional.ofNullable(IdentityTenantUtil.getTenantDomainFromContext())
.filter(StringUtils::isNotBlank)
.orElseGet(() -> PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain());
}

/**
* Regenerate consumer secret for the application and retrieve application details.
*
Expand All @@ -847,6 +979,11 @@ public OAuthConsumerAppDTO updateAndRetrieveOauthSecretKey(String consumerKey) t

Properties properties = new Properties();
String newSecret = OAuthUtil.getRandomNumberSecure();
OAuthConsumerAppDTO oldAppDTO = null;

if (ApplicationMgtUtil.isLegacyAuditLogsDisabledInAppMgt()) {
oldAppDTO = getOAuthApplicationData(consumerKey);
}
properties.setProperty(OAuthConstants.OAUTH_APP_NEW_SECRET_KEY, newSecret);
properties.setProperty(OAuthConstants.ACTION_PROPERTY_KEY, OAuthConstants.ACTION_REGENERATE);
properties.setProperty(OAuthConstants.OAUTH_APP_NEW_STATE, APP_STATE_ACTIVE);
Expand All @@ -860,9 +997,26 @@ public OAuthConsumerAppDTO updateAndRetrieveOauthSecretKey(String consumerKey) t

OAuthConsumerAppDTO updatedApplication = getOAuthApplicationData(consumerKey);
updatedApplication.setOauthConsumerSecret(newSecret);

if (ApplicationMgtUtil.isLegacyAuditLogsDisabledInAppMgt()) {
// This API is invoked when regenerating client secret and when activating the app.
Optional<String> initiatorId = getInitiatorId();
if (initiatorId.isPresent()) {
if (!StringUtils.equalsIgnoreCase(oldAppDTO.getState(), APP_STATE_ACTIVE)) {
AuditLog.AuditLogBuilder auditLogBuilder = new AuditLog.AuditLogBuilder(
initiatorId.get(), USER, consumerKey, TARGET_APPLICATION,
OAuthConstants.LogConstants.UPDATE_APP_STATE)
.data(Map.of("state", APP_STATE_ACTIVE));
triggerAuditLogEvent(auditLogBuilder, true);
}
AuditLog.AuditLogBuilder auditLogBuilder = new AuditLog.AuditLogBuilder(
initiatorId.get(), USER, consumerKey, TARGET_APPLICATION,
OAuthConstants.LogConstants.REGENERATE_CLIENT_SECRET);
triggerAuditLogEvent(auditLogBuilder, true);
} else {
LOG.error("Error getting the logged in userId");
}
}
return updatedApplication;

}

void updateAppAndRevokeTokensAndAuthzCodes(String consumerKey,
Expand Down Expand Up @@ -977,7 +1131,17 @@ public void removeOAuthApplicationData(String consumerKey) throws IdentityOAuthA
if (LOG.isDebugEnabled()) {
LOG.debug("Client credentials are removed from the cache for OAuth App with consumerKey: " + consumerKey);
}

if (ApplicationMgtUtil.isLegacyAuditLogsDisabledInAppMgt()) {
Optional<String> initiatorId = getInitiatorId();
if (initiatorId.isPresent()) {
AuditLog.AuditLogBuilder auditLogBuilder = new AuditLog.AuditLogBuilder(
initiatorId.get(), USER, consumerKey, TARGET_APPLICATION,
OAuthConstants.LogConstants.DELETE_OAUTH_APPLICATION);
triggerAuditLogEvent(auditLogBuilder, true);
} else {
LOG.error("Error getting the logged in userId");
}
}
}

/**
Expand Down Expand Up @@ -1240,7 +1404,7 @@ public OAuthRevocationResponseDTO revokeIssuedTokensByApplication(OAuthAppRevoca
return revokeRespDTO;
}

String tenantDomain = getTenantDomain(consumerKey);
String tenantDomain = getLoggedInTenant(consumerKey);
String applicationName = getApplicationName(consumerKey, tenantDomain);
List<AccessTokenDO> accessTokenDOs = getActiveAccessTokensByConsumerKey(consumerKey);
if (accessTokenDOs.size() > 0) {
Expand Down Expand Up @@ -1388,7 +1552,7 @@ private void revokeAccessTokens(String[] accessTokens, String consumerKey, Strin
}
}

private String getTenantDomain(String consumerKey) throws IdentityOAuthAdminException {
private String getLoggedInTenant(String consumerKey) throws IdentityOAuthAdminException {

String tenantDomain;
try {
Expand Down
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -857,13 +857,13 @@
<apache.felix.scr.ds.annotations.version>1.2.4</apache.felix.scr.ds.annotations.version>

<!-- Carbon kernel version -->
<carbon.kernel.version>4.9.1</carbon.kernel.version>
<carbon.kernel.feature.version>4.9.1</carbon.kernel.feature.version>
<carbon.kernel.version>4.9.10</carbon.kernel.version>
<carbon.kernel.feature.version>4.9.7</carbon.kernel.feature.version>
<carbon.kernel.imp.pkg.version.range>[4.5.0, 5.0.0)</carbon.kernel.imp.pkg.version.range>
<carbon.kernel.registry.imp.pkg.version.range>[1.0.1, 2.0.0)</carbon.kernel.registry.imp.pkg.version.range>

<!-- Carbon Identity Framework version -->
<carbon.identity.framework.version>5.25.234</carbon.identity.framework.version>
<carbon.identity.framework.version>5.25.258</carbon.identity.framework.version>
<carbon.identity.framework.imp.pkg.version.range>[5.25.234, 7.0.0)
</carbon.identity.framework.imp.pkg.version.range>

Expand Down

0 comments on commit 67f2e33

Please sign in to comment.