use of org.wso2.carbon.apimgt.impl.kmclient.model.TokenInfo in project carbon-apimgt by wso2.
the class DefaultKeyValidationHandler method getAccessTokenInfo.
private AccessTokenInfo getAccessTokenInfo(TokenValidationContext validationContext) throws APIManagementException {
Object cachedAccessTokenInfo = CacheProvider.createIntrospectionCache().get(validationContext.getAccessToken());
if (cachedAccessTokenInfo != null) {
log.debug("AccessToken available in introspection Cache.");
return (AccessTokenInfo) cachedAccessTokenInfo;
}
String electedKeyManager = null;
// Obtaining details about the token.
if (StringUtils.isNotEmpty(validationContext.getTenantDomain())) {
Map<String, KeyManagerDto> tenantKeyManagers = KeyManagerHolder.getTenantKeyManagers(validationContext.getTenantDomain());
KeyManager keyManagerInstance = null;
if (tenantKeyManagers.values().size() == 1) {
log.debug("KeyManager count is 1");
Map.Entry<String, KeyManagerDto> entry = tenantKeyManagers.entrySet().iterator().next();
if (entry != null) {
KeyManagerDto keyManagerDto = entry.getValue();
if (keyManagerDto != null && (validationContext.getKeyManagers().contains(APIConstants.KeyManager.API_LEVEL_ALL_KEY_MANAGERS) || validationContext.getKeyManagers().contains(keyManagerDto.getName()))) {
if (log.isDebugEnabled()) {
log.debug("KeyManager " + keyManagerDto.getName() + " Available in API level KM list " + String.join(",", validationContext.getKeyManagers()));
}
if (keyManagerDto.getKeyManager() != null && keyManagerDto.getKeyManager().canHandleToken(validationContext.getAccessToken())) {
if (log.isDebugEnabled()) {
log.debug("KeyManager " + keyManagerDto.getName() + " can handle the token");
}
keyManagerInstance = keyManagerDto.getKeyManager();
electedKeyManager = entry.getKey();
}
}
}
} else if (tenantKeyManagers.values().size() > 1) {
log.debug("KeyManager count is > 1");
if (validationContext.getKeyManagers().contains(APIConstants.KeyManager.API_LEVEL_ALL_KEY_MANAGERS)) {
if (log.isDebugEnabled()) {
log.debug("API level KeyManagers contains " + APIConstants.KeyManager.API_LEVEL_ALL_KEY_MANAGERS);
}
for (Map.Entry<String, KeyManagerDto> keyManagerDtoEntry : tenantKeyManagers.entrySet()) {
if (keyManagerDtoEntry.getValue().getKeyManager() != null && keyManagerDtoEntry.getValue().getKeyManager().canHandleToken(validationContext.getAccessToken())) {
if (log.isDebugEnabled()) {
log.debug("KeyManager " + keyManagerDtoEntry.getValue().getName() + " can handle the token");
}
keyManagerInstance = keyManagerDtoEntry.getValue().getKeyManager();
electedKeyManager = keyManagerDtoEntry.getKey();
break;
}
}
} else {
for (String selectedKeyManager : validationContext.getKeyManagers()) {
KeyManagerDto keyManagerDto = tenantKeyManagers.get(selectedKeyManager);
if (keyManagerDto != null && keyManagerDto.getKeyManager() != null && keyManagerDto.getKeyManager().canHandleToken(validationContext.getAccessToken())) {
if (log.isDebugEnabled()) {
log.debug("KeyManager " + keyManagerDto.getName() + " can handle the token");
}
keyManagerInstance = keyManagerDto.getKeyManager();
electedKeyManager = selectedKeyManager;
break;
}
}
}
}
if (keyManagerInstance != null) {
log.debug("KeyManager instance available to validate token.");
AccessTokenInfo tokenInfo = keyManagerInstance.getTokenMetaData(validationContext.getAccessToken());
tokenInfo.setKeyManager(electedKeyManager);
CacheProvider.getGatewayIntrospectCache().put(validationContext.getAccessToken(), tokenInfo);
return tokenInfo;
} else {
AccessTokenInfo tokenInfo = new AccessTokenInfo();
tokenInfo.setTokenValid(false);
tokenInfo.setErrorcode(APIConstants.KeyValidationStatus.API_AUTH_INVALID_CREDENTIALS);
log.debug("KeyManager not available to authorize token.");
return tokenInfo;
}
}
return null;
}
use of org.wso2.carbon.apimgt.impl.kmclient.model.TokenInfo in project carbon-apimgt by wso2.
the class AMDefaultKeyManagerImpl method getTokenMetaData.
@Override
public AccessTokenInfo getTokenMetaData(String accessToken) throws APIManagementException {
AccessTokenInfo tokenInfo = new AccessTokenInfo();
try {
IntrospectInfo introspectInfo = introspectionClient.introspect(accessToken);
tokenInfo.setAccessToken(accessToken);
boolean isActive = introspectInfo.isActive();
if (!isActive) {
tokenInfo.setTokenValid(false);
tokenInfo.setErrorcode(APIConstants.KeyValidationStatus.API_AUTH_INVALID_CREDENTIALS);
return tokenInfo;
}
tokenInfo.setTokenValid(true);
if (introspectInfo.getIat() > 0 && introspectInfo.getExpiry() > 0) {
if (introspectInfo.getExpiry() != Long.MAX_VALUE) {
long validityPeriod = introspectInfo.getExpiry() - introspectInfo.getIat();
tokenInfo.setValidityPeriod(validityPeriod * 1000L);
} else {
tokenInfo.setValidityPeriod(Long.MAX_VALUE);
}
tokenInfo.setIssuedTime(introspectInfo.getIat() * 1000L);
}
if (StringUtils.isNotEmpty(introspectInfo.getScope())) {
String[] scopes = introspectInfo.getScope().split(" ");
tokenInfo.setScope(scopes);
}
tokenInfo.setConsumerKey(introspectInfo.getClientId());
String username = introspectInfo.getUsername();
if (!StringUtils.isEmpty(username)) {
tokenInfo.setEndUserName(username);
}
return tokenInfo;
} catch (KeyManagerClientException e) {
throw new APIManagementException("Error occurred in token introspection!", e);
}
}
use of org.wso2.carbon.apimgt.impl.kmclient.model.TokenInfo in project carbon-apimgt by wso2.
the class AMDefaultKeyManagerImpl method getNewApplicationAccessToken.
@Override
public AccessTokenInfo getNewApplicationAccessToken(AccessTokenRequest tokenRequest) throws APIManagementException {
AccessTokenInfo tokenInfo;
if (tokenRequest == null) {
log.warn("No information available to generate Token.");
return null;
}
// When validity time set to a negative value, a token is considered never to expire.
if (tokenRequest.getValidityPeriod() == OAuthConstants.UNASSIGNED_VALIDITY_PERIOD) {
// Setting a different -ve value if the set value is -1 (-1 will be ignored by TokenValidator)
tokenRequest.setValidityPeriod(-2L);
}
// Generate New Access Token
String scopes = String.join(" ", tokenRequest.getScope());
TokenInfo tokenResponse;
try {
String credentials = tokenRequest.getClientId() + ':' + tokenRequest.getClientSecret();
String authToken = Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8));
if (APIConstants.OAuthConstants.TOKEN_EXCHANGE.equals(tokenRequest.getGrantType())) {
tokenResponse = authClient.generate(tokenRequest.getClientId(), tokenRequest.getClientSecret(), tokenRequest.getGrantType(), scopes, (String) tokenRequest.getRequestParam(APIConstants.OAuthConstants.SUBJECT_TOKEN), APIConstants.OAuthConstants.JWT_TOKEN_TYPE);
} else {
tokenResponse = authClient.generate(authToken, GRANT_TYPE_VALUE, scopes);
}
} catch (KeyManagerClientException e) {
throw new APIManagementException("Error occurred while calling token endpoint - " + e.getReason(), e);
}
tokenInfo = new AccessTokenInfo();
if (StringUtils.isNotEmpty(tokenResponse.getScope())) {
tokenInfo.setScope(tokenResponse.getScope().split(" "));
} else {
tokenInfo.setScope(new String[0]);
}
tokenInfo.setAccessToken(tokenResponse.getToken());
tokenInfo.setValidityPeriod(tokenResponse.getExpiry());
return tokenInfo;
}
use of org.wso2.carbon.apimgt.impl.kmclient.model.TokenInfo in project carbon-apimgt by wso2.
the class OAuthOpaqueAuthenticatorImpl method authenticate.
/**
* @param message cxf message to be authenticated
* @return true if authentication was successful else false
* @throws APIManagementException when error in authentication process
*/
@Override
public boolean authenticate(Message message) throws APIManagementException {
boolean retrievedFromInvalidTokenCache = false;
boolean retrievedFromTokenCache = false;
String accessToken = RestApiUtil.extractOAuthAccessTokenFromMessage(message, RestApiConstants.REGEX_BEARER_PATTERN, RestApiConstants.AUTH_HEADER_NAME);
OAuthTokenInfo tokenInfo = null;
RESTAPICacheConfiguration cacheConfiguration = APIUtil.getRESTAPICacheConfig();
// validate the token from cache if it is enabled
if (cacheConfiguration.isTokenCacheEnabled()) {
tokenInfo = (OAuthTokenInfo) getRESTAPITokenCache().get(accessToken);
if (tokenInfo != null) {
if (isAccessTokenExpired(tokenInfo)) {
tokenInfo.setTokenValid(false);
// remove the token from token cache and put the token into invalid token cache
// when the access token is expired
getRESTAPIInvalidTokenCache().put(accessToken, tokenInfo);
getRESTAPITokenCache().remove(accessToken);
log.error(RestApiConstants.ERROR_TOKEN_EXPIRED);
return false;
} else {
retrievedFromTokenCache = true;
}
} else {
// if the token doesn't exist in the valid token cache, then check it in the invalid token cache
tokenInfo = (OAuthTokenInfo) getRESTAPIInvalidTokenCache().get(accessToken);
if (tokenInfo != null) {
retrievedFromInvalidTokenCache = true;
}
}
}
// if the tokenInfo is null, then only retrieve the token information from the database
try {
if (tokenInfo == null) {
tokenInfo = getTokenMetaData(accessToken);
}
} catch (APIManagementException e) {
log.error("Error while retrieving token information for token: " + accessToken, e);
}
// if we got valid access token we will proceed with next
if (tokenInfo != null && tokenInfo.isTokenValid()) {
if (cacheConfiguration.isTokenCacheEnabled() && !retrievedFromTokenCache) {
// put the token info into token cache
getRESTAPITokenCache().put(accessToken, tokenInfo);
}
// If access token is valid then we will perform scope check for given resource.
if (validateScopes(message, tokenInfo)) {
// Add the user scopes list extracted from token to the cxf message
message.getExchange().put(RestApiConstants.USER_REST_API_SCOPES, tokenInfo.getScopes());
// If scope validation successful then set tenant name and user name to current context
String tenantDomain = MultitenantUtils.getTenantDomain(tokenInfo.getEndUserName());
int tenantId;
PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
RealmService realmService = (RealmService) carbonContext.getOSGiService(RealmService.class, null);
try {
String username = tokenInfo.getEndUserName();
if (MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
// when the username is an email in supertenant, it has at least 2 occurrences of '@'
long count = username.chars().filter(ch -> ch == '@').count();
// in the case of email, there will be more than one '@'
boolean isEmailUsernameEnabled = Boolean.parseBoolean(CarbonUtils.getServerConfiguration().getFirstProperty("EnableEmailUserName"));
if (isEmailUsernameEnabled || (username.endsWith(SUPER_TENANT_SUFFIX) && count <= 1)) {
username = MultitenantUtils.getTenantAwareUsername(username);
}
}
if (log.isDebugEnabled()) {
log.debug("username = " + username);
}
tenantId = realmService.getTenantManager().getTenantId(tenantDomain);
carbonContext.setTenantDomain(tenantDomain);
carbonContext.setTenantId(tenantId);
carbonContext.setUsername(username);
message.put(RestApiConstants.SUB_ORGANIZATION, tenantDomain);
if (!tenantDomain.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) {
APIUtil.loadTenantConfigBlockingMode(tenantDomain);
}
return true;
} catch (UserStoreException e) {
log.error("Error while retrieving tenant id for tenant domain: " + tenantDomain, e);
}
} else {
log.error(RestApiConstants.ERROR_SCOPE_VALIDATION_FAILED);
}
} else {
log.error(RestApiConstants.ERROR_TOKEN_INVALID);
if (cacheConfiguration.isTokenCacheEnabled() && !retrievedFromInvalidTokenCache) {
getRESTAPIInvalidTokenCache().put(accessToken, tokenInfo);
}
}
return false;
}
use of org.wso2.carbon.apimgt.impl.kmclient.model.TokenInfo in project carbon-apimgt by wso2.
the class AbstractOAuthAuthenticator method validateScopes.
/**
* @param message CXF message to be validate
* @param tokenInfo Token information associated with incoming request
* @return return true if we found matching scope in resource and token information
* else false(means scope validation failed).
*/
@MethodStats
public boolean validateScopes(Message message, OAuthTokenInfo tokenInfo) {
String basePath = (String) message.get(Message.BASE_PATH);
// path is obtained from Message.REQUEST_URI instead of Message.PATH_INFO, as Message.PATH_INFO contains
// decoded values of request parameters
String path = (String) message.get(Message.REQUEST_URI);
String verb = (String) message.get(Message.HTTP_REQUEST_METHOD);
String resource = path.substring(basePath.length() - 1);
String[] scopes = tokenInfo.getScopes();
String version = (String) message.get(RestApiConstants.API_VERSION);
// get all the URI templates of the REST API from the base path
Set<URITemplate> uriTemplates = RestApiUtil.getURITemplatesForBasePath(basePath + version);
if (uriTemplates.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("No matching scopes found for request with path: " + basePath + ". Skipping scope validation.");
}
return true;
}
for (Object template : uriTemplates.toArray()) {
org.wso2.uri.template.URITemplate templateToValidate = null;
Map<String, String> var = new HashMap<String, String>();
// check scopes with what we have
String templateString = ((URITemplate) template).getUriTemplate();
try {
templateToValidate = new org.wso2.uri.template.URITemplate(templateString);
} catch (URITemplateException e) {
log.error("Error while creating URI Template object to validate request. Template pattern: " + templateString, e);
}
if (templateToValidate != null && templateToValidate.matches(resource, var) && scopes != null && verb != null && verb.equalsIgnoreCase(((URITemplate) template).getHTTPVerb())) {
for (String scope : scopes) {
Scope scp = ((URITemplate) template).getScope();
if (scp != null) {
if (scope.equalsIgnoreCase(scp.getKey())) {
// we found scopes matches
if (log.isDebugEnabled()) {
log.debug("Scope validation successful for access token: " + message.get(RestApiConstants.MASKED_TOKEN) + " with scope: " + scp.getKey() + " for resource path: " + path + " and verb " + verb);
}
return true;
}
} else if (!((URITemplate) template).retrieveAllScopes().isEmpty()) {
List<Scope> scopesList = ((URITemplate) template).retrieveAllScopes();
for (Scope scpObj : scopesList) {
if (scope.equalsIgnoreCase(scpObj.getKey())) {
// we found scopes matches
if (log.isDebugEnabled()) {
log.debug("Scope validation successful for access token: " + message.get(RestApiConstants.MASKED_TOKEN) + " with scope: " + scpObj.getKey() + " for resource path: " + path + " and verb " + verb);
}
return true;
}
}
} else {
if (log.isDebugEnabled()) {
log.debug("Scope not defined in swagger for matching resource " + resource + " and verb " + verb + " . So consider as anonymous permission and let request to continue.");
}
return true;
}
}
}
}
return false;
}
Aggregations