Skip to content
Snippets Groups Projects
Commit 66eef7e3 authored by Alok Joshi's avatar Alok Joshi
Browse files

Merge branch 'cache_ent' into 'master'

Add cache for entitlements authorize mechanism

See merge request !553
parents 43b308a5 73fbe24b
No related branches found
No related tags found
1 merge request!553Add cache for entitlements authorize mechanism
Pipeline #308458 failed
......@@ -17,10 +17,13 @@
package org.opengroup.osdu.notification.auth;
import org.apache.commons.lang3.StringUtils;
import org.opengroup.osdu.core.common.cache.ICache;
import org.opengroup.osdu.core.common.model.entitlements.AuthorizationResponse;
import org.opengroup.osdu.core.common.model.entitlements.Groups;
import org.opengroup.osdu.core.common.model.http.AppException;
import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.opengroup.osdu.core.common.provider.interfaces.IAuthorizationService;
import org.opengroup.osdu.core.common.util.Crc32c;
import org.opengroup.osdu.notification.di.RequestInfoExt;
import org.opengroup.osdu.notification.utils.Config;
import org.opengroup.osdu.notification.provider.interfaces.IServiceAccountValidator;
......@@ -44,6 +47,8 @@ public class AuthorizationFilter {
private RequestInfoExt requestInfoExt;
@Autowired
private IServiceAccountValidator validator;
@Autowired
private ICache<String, Groups> cache;
public boolean hasAnyPermission(String... requiredRoles) {
DpsHeaders dpsHeaders = requestInfoExt.getHeaders();
......@@ -66,20 +71,45 @@ public class AuthorizationFilter {
} else if (Arrays.asList(requiredRoles).contains(Config.PUBSUB)) {
String jwt = dpsHeaders.getAuthorization().substring(BEARER_PREFIX.length());
if (!this.validator.isValidPublisherServiceAccount(jwt)) {
this.authorizeWithEntitlements(requiredRoles);
return this.authorizeWithCacheOrEntitlements(requiredRoles, dpsHeaders);
} else {
return false;
}
} else {
authorizeWithEntitlements(requiredRoles);
return this.authorizeWithCacheOrEntitlements(requiredRoles, dpsHeaders);
}
return true;
}
private void authorizeWithEntitlements(String... requiredRoles) {
DpsHeaders dpsHeaders = requestInfoExt.getHeaders();
private boolean authorizeWithCacheOrEntitlements(String[] requiredRoles, DpsHeaders dpsHeaders) {
String cacheKey = getGroupCacheKey(dpsHeaders);
Groups groups = cache.get(cacheKey);
if(groups == null) {
AuthorizationResponse authorizationResponse = this.authorizeWithEntitlements(requiredRoles, dpsHeaders);
cache.put(cacheKey, authorizationResponse.getGroups());
return true;
} else {
return authorizeWithCache(requiredRoles, groups);
}
}
private boolean authorizeWithCache(String[] requiredRoles, Groups groups) {
if(groups.any(requiredRoles)) {
return true;
}
return false;
}
private String getGroupCacheKey(DpsHeaders dpsHeaders) {
String key = String.format("notification-entitlement-groups:%s:%s", dpsHeaders.getPartitionIdWithFallbackToAccountId(),
dpsHeaders.getAuthorization());
return Crc32c.hashToBase64EncodedString(key);
}
private AuthorizationResponse authorizeWithEntitlements(String[] requiredRoles, DpsHeaders dpsHeaders) {
AuthorizationResponse authorizationResponse = authService.authorizeAny(dpsHeaders, requiredRoles);
dpsHeaders.put(DpsHeaders.USER_EMAIL, authorizationResponse.getUser());
requestInfoExt.setHeaders(dpsHeaders);
return authorizationResponse;
}
}
// Copyright 2017-2025, SLB
//
// 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.
package org.opengroup.osdu.notification.cache;
import org.opengroup.osdu.core.common.cache.VmCache;
import org.opengroup.osdu.core.common.model.entitlements.Groups;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnProperty(value = "cache.provider", havingValue = "vm", matchIfMissing = true)
public class GroupVmCache {
@Bean
public VmCache<String, Groups> groupCache(@Value("${group.cache.expiration:30}") final int expiration,
@Value("${group.cache.maxSize:1000}") final int maxSize) {
return new VmCache<>(expiration, maxSize);
}
}
\ No newline at end of file
......@@ -21,7 +21,10 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.opengroup.osdu.core.common.cache.ICache;
import org.opengroup.osdu.core.common.model.entitlements.AuthorizationResponse;
import org.opengroup.osdu.core.common.model.entitlements.GroupInfo;
import org.opengroup.osdu.core.common.model.entitlements.Groups;
import org.opengroup.osdu.core.common.model.http.AppException;
import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.opengroup.osdu.core.common.provider.interfaces.IAuthorizationService;
......@@ -32,13 +35,17 @@ import org.opengroup.osdu.notification.utils.Config;
import org.powermock.modules.junit4.PowerMockRunner;
import jakarta.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
......@@ -69,6 +76,9 @@ public class AuthorizationFilterTest {
@Mock
private IPubsubRequestBodyExtractor extractor;
@Mock
private ICache<String, Groups> cache;
@InjectMocks
private AuthorizationFilter sut;
......@@ -142,4 +152,21 @@ public class AuthorizationFilterTest {
this.sut.hasAnyPermission(ROLE4, ROLE2);
verify(headers).put(DpsHeaders.USER_EMAIL, USER_EMAIL);
}
@Test
public void should_authenticateRequest_when_groupsAreAvailableInCache() {
Groups groups = new Groups();
List<GroupInfo> groupInfos = new ArrayList<>();
GroupInfo groupInfo = new GroupInfo();
groupInfo.setEmail("groupInfoEmail");
groupInfo.setDescription("description");
groupInfo.setName("role1");
groupInfos.add(groupInfo);
groups.setGroups(groupInfos);
groups.setDesId("desid");
groups.setMemberEmail("memberEmail");
when(this.cache.get("8Z2MjQ==")).thenReturn(groups);
assertTrue(this.sut.hasAnyPermission(ROLE1, ROLE2));
verify(authorizationService, never()).authorizeAny(any(DpsHeaders.class), any(String[].class));
}
}
// Copyright 2017-2025, SLB
//
// 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.
package org.opengroup.osdu.notification.provider.azure.cache;
import org.opengroup.osdu.azure.cache.RedisAzureCache;
import org.opengroup.osdu.azure.di.RedisAzureConfiguration;
import org.opengroup.osdu.core.common.model.entitlements.Groups;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnProperty(value = "cache.provider", havingValue = "redis")
public class GroupRedisCache {
@Value("${redis.port:6380}")
private int port;
@Value("${group.cache.expiration:30}")
public int groupRedisTtl;
@Value("${redis.database}")
private int database;
@Value("${redis.connection.timeout:15}")
private int timeout;
@Value("${redis.command.timeout:5}")
private int commandTimeout;
@Bean
public RedisAzureCache<String, Groups> groupCache() {
return new RedisAzureCache<>(String.class, Groups.class, new RedisAzureConfiguration(database, groupRedisTtl, port, timeout, commandTimeout));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment