Skip to content

Commit

Permalink
Added IsAuthorisedUser function to check whether user session is auth…
Browse files Browse the repository at this point in the history
…orised to access path and method
  • Loading branch information
linxiaoxin committed Jul 17, 2024
1 parent afdb6e1 commit 4c8f249
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 16 deletions.
1 change: 1 addition & 0 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ jobs:
build/reports/
zap_scan:
if: false
permissions: write-all
needs: deploy_to_ecs
runs-on: ubuntu-latest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,9 @@ public ResponseEntity<Boolean> isAuthorised(@RequestBody IsAuthorisedRequest req
var result =authenticationService.checkAccess(request.getRole(), request.getPath(), request.getMethod());
return ResponseEntity.status(HttpStatus.OK).body(result);
}
@PostMapping("isauthoriseduser")
public ResponseEntity<Boolean> isAuthorisedUser(@RequestBody IsAuthorisedRequest request){
var result =authenticationService.checkUserSessionAccess(request.getSessionId(), request.getPath(), request.getMethod());
return ResponseEntity.status(HttpStatus.OK).body(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ public class IsAuthorisedRequest {
private String role;
private String path;
private String method;
private String sessionId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;
import java.util.Optional;

public interface RoleRepository extends JpaRepository<Role, Long> {

@Query("select r from Role r left join fetch r.grantedWith where r.name = :name")
Optional<Role> findByName(@Param("name") String name);

@Query("select r from Role r left join fetch r.grantedWith where r.name in :names")
List<Role> findByNames(@Param("name") String[] names);
}

Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ public interface AuthenticationService {
void signOut(String sessionId, String clientId);

Boolean checkAccess(String roleName, String path, String method);

Boolean checkUserSessionAccess(String sessionId, String path, String method);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Map;
import java.util.UUID;
Expand Down Expand Up @@ -69,10 +70,16 @@ public UserProfile getAccessToken(TokenRequest request) {
ObjectMapper mapper = new ObjectMapper();
try {
Map<String, Object> map = mapper.readValue(payload, new TypeReference<>() {});

//creates session id as key and store user profile and access tokens info in redis
user = new UserProfile();
user.setSessionId(UUID.randomUUID().toString());
user.setEmail((String)map.get("email"));
var useRoles = (ArrayList<Object>)map.get("cognito:groups");
if(useRoles != null) {
var roles = useRoles.toArray(new String[useRoles.size()]);
user.setRoles(roles);
}

redisTemplate.opsForValue().set(user.getSessionId()+"_profile", user, Duration.ofSeconds(SESSION_TIMEOUT));
redisTemplate.opsForValue().set(user.getSessionId()+"_tokens", response.getBody(), Duration.ofSeconds(SESSION_TIMEOUT));
Expand Down Expand Up @@ -112,14 +119,30 @@ public void signOut(String sessionId, String clientId) {
@Override
public Boolean checkAccess(String roleName, String path, String method) {
//get role
var teacher = roleRepository.findByName(roleName);
if(teacher.isPresent()){
var grantedWith = teacher.get().getGrantedWith();
var role = roleRepository.findByName(roleName);
if(role.isPresent()){
var grantedWith = role.get().getGrantedWith();
if(grantedWith.stream().anyMatch(granted -> granted.getPath().compareToIgnoreCase(path) == 0
&& granted.getMethod().compareToIgnoreCase(method) ==0))
return true;
}
return false;
}

@Override
public Boolean checkUserSessionAccess(String sessionId, String path, String method) {
//get user profile role
var profile = ((UserProfile) redisTemplate.opsForValue().get(sessionId + "_profile"));
if(profile == null)
return false;

//get role
var roles = roleRepository.findByNames(profile.getRoles());
if(roles.stream().anyMatch(role ->
role.getGrantedWith().stream().anyMatch(granted -> granted.getPath().compareToIgnoreCase(path) == 0
&& granted.getMethod().compareToIgnoreCase(method) == 0))){
return true;
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ void givenSignOut_Success() throws Exception{
@Test
void givenisAuthorised_Success() throws Exception{
var request = new IsAuthorisedRequest();
request.setRole("teacher");
request.setRole("tutor");
request.setPath("/questions");
request.setMethod("GET");

Expand All @@ -125,4 +125,25 @@ void givenisAuthorised_Success() throws Exception{

Assertions.assertEquals("true", result.getResponse().getContentAsString());
}

@Test
void givenisAuthorisedUser_Success() throws Exception{
var request = new IsAuthorisedRequest();
request.setRole("tutor");
request.setPath("/questions");
request.setMethod("GET");

ObjectMapper mapper = new ObjectMapper();

given(authenticationService.checkUserSessionAccess(request.getSessionId(), request.getPath(), request.getMethod()))
.willReturn(true);

var result = mockMvc.perform(post("/v1/auth/isauthoriseduser")
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(request)))
.andExpect(status().isOk())
.andReturn();

Assertions.assertEquals("true", result.getResponse().getContentAsString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.*;

//@WebMvcTest(AuthenticationService.class)
@ContextConfiguration(classes = {RestClientConfig.class, RedisConfig.class})
Expand Down Expand Up @@ -64,10 +61,11 @@ void init() throws NoSuchFieldException, IllegalAccessException {

user = new UserProfile();
user.setEmail("[email protected]");
user.setRoles(new String[]{"tutor", "admin"});
user.setSessionId(UUID.randomUUID().toString());

//idtoken with email set as [email protected]
idToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJlbWFpbCI6InRlc3RVc2VyQGVtYWlsLmNvbSJ9.cI8ybuRu1FP7_jR9-mHuS2w9EBVueQRMR5DeF2C3pWc";
idToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdF9oYXNoIjoidThRdnNKdFY1TXRETFdodF9xQmFpZyIsInN1YiI6ImM5YWFkNTRjLTYwZTEtNzA0NS1lNzEyLTlhZDFkYTczZjg3YSIsImNvZ25pdG86Z3JvdXBzIjpbInR1dG9yIiwiYWRtaW4iXSwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJpc3MiOiJodHRwczovL2NvZ25pdG8taWRwLmFwLXNvdXRoZWFzdC0xLmFtYXpvbmF3cy5jb20vYXAtc291dGhlYXN0LTFfWmIwSmwwN1dzIiwiY29nbml0bzp1c2VybmFtZSI6Imdvb2dsZV8xMDQwMjk0OTE2Njc5NjE1ODg4NDAiLCJvcmlnaW5fanRpIjoiYTY1M2ExMDEtNTUyMi00ZDIyLTk1NzctZGZkZjA4ZDM5NDc4IiwiYXVkIjoiMXEzMHZtZDB2Y2VlNmsxbHJwMmluMTA2MjMiLCJpZGVudGl0aWVzIjpbeyJkYXRlQ3JlYXRlZCI6IjE3MTcyNTI0Mzk3MDMiLCJ1c2VySWQiOiIxMDQwMjk0OTE2Njc5NjE1ODg4NDAiLCJwcm92aWRlck5hbWUiOiJHb29nbGUiLCJwcm92aWRlclR5cGUiOiJHb29nbGUiLCJpc3N1ZXIiOm51bGwsInByaW1hcnkiOiJ0cnVlIn1dLCJ0b2tlbl91c2UiOiJpZCIsImF1dGhfdGltZSI6MTcyMTE0MDE3NywiZXhwIjoxNzIxMTQxMDc3LCJpYXQiOjE3MjExNDAxNzcsImp0aSI6IjU5YjlkZmZlLWFkMjItNDMyZC05ZWIxLTRiZmVhYjFhOGY4MyIsImVtYWlsIjoidGVzdFVzZXJAZW1haWwuY29tIn0.HabZEsulPCsu-IYRE_G42RUWo0k5jMJqYSxJx_QgtuY";
tokenResponse = new TokenResponse();
tokenResponse.setIdToken(idToken);
tokenResponse.setAccessToken("testAccessToken");
Expand Down Expand Up @@ -105,8 +103,11 @@ void givenGetAccessToken_Success(){

var result = authenticationService.getAccessToken(tokenRequest);
tokenResponse.setEmail("[email protected]");

Assertions.assertEquals(user.getEmail(), result.getEmail() );
}
Assertions.assertEquals(user.getRoles().length, result.getRoles().length );

}

@Test
void givenSignOut_Success(){
Expand Down Expand Up @@ -136,11 +137,11 @@ void givenCheckAccess_Success(){

grantedWith.add(apiResource);
var role = new Role();
role.setName("teacher");
role.setName("tutor");
role.setGrantedWith(grantedWith);

Mockito.when(roleRepository.findByName("teacher")).thenReturn(Optional.of(role));
var result = authenticationService.checkAccess("teacher", "/questions", "GET");
Mockito.when(roleRepository.findByName("tutor")).thenReturn(Optional.of(role));
var result = authenticationService.checkAccess("tutor", "/questions", "GET");

Assertions.assertEquals(result, true);
}
Expand All @@ -154,11 +155,86 @@ void givenCheckAccess_DenyAccess(){

grantedWith.add(apiResource);
var role = new Role();
role.setName("teacher");
role.setName("tutor");
role.setGrantedWith(grantedWith);

Mockito.when(roleRepository.findByName(role.getName())).thenReturn(Optional.of(role));
var result = authenticationService.checkAccess("tutor", "/questions", "POST");

Assertions.assertEquals(result, false);
}

@Test
void givencheckUserSessionAccess_Success(){
Set<ApiResource> grantedWith = new HashSet<>();
var apiResource = new ApiResource();
apiResource.setPath("/questions");
apiResource.setMethod("GET");

grantedWith.add(apiResource);
var role = new Role();
role.setName("tutor");
role.setGrantedWith(grantedWith);

var roles = new ArrayList<Role>();
roles.add(role);

Mockito.when(redisTemplate.opsForValue()).thenReturn(valueOperations);
Mockito.when(redisTemplate.opsForValue().get(user.getSessionId()+"_profile"))
.thenReturn(user);

Mockito.when(roleRepository.findByNames(user.getRoles())).thenReturn(roles);
var result = authenticationService.checkUserSessionAccess(user.getSessionId(), "/questions", "GET");

Assertions.assertEquals(result, true);
}

@Test
void givencheckUserSessionAccess_InValidSession(){
Set<ApiResource> grantedWith = new HashSet<>();
var apiResource = new ApiResource();
apiResource.setPath("/questions");
apiResource.setMethod("GET");

grantedWith.add(apiResource);
var role = new Role();
role.setName("tutor");
role.setGrantedWith(grantedWith);

Mockito.when(roleRepository.findByName("teacher")).thenReturn(Optional.of(role));
var result = authenticationService.checkAccess("teacher", "/questions", "POST");
var roles = new ArrayList<Role>();
roles.add(role);

Mockito.when(redisTemplate.opsForValue()).thenReturn(valueOperations);
Mockito.when(redisTemplate.opsForValue().get(user.getSessionId()+"_profile"))
.thenReturn(null);

Mockito.when(roleRepository.findByNames(user.getRoles())).thenReturn(roles);
var result = authenticationService.checkUserSessionAccess(user.getSessionId(), "/questions", "GET");

Assertions.assertEquals(result, false);
}

@Test
void givencheckUserSessionAccess_NoAccess(){
Set<ApiResource> grantedWith = new HashSet<>();
var apiResource = new ApiResource();
apiResource.setPath("/questions");
apiResource.setMethod("GET");

grantedWith.add(apiResource);
var role = new Role();
role.setName("tutor");
role.setGrantedWith(grantedWith);

var roles = new ArrayList<Role>();
roles.add(role);

Mockito.when(redisTemplate.opsForValue()).thenReturn(valueOperations);
Mockito.when(redisTemplate.opsForValue().get(user.getSessionId()+"_profile"))
.thenReturn(null);

Mockito.when(roleRepository.findByNames(user.getRoles())).thenReturn(roles);
var result = authenticationService.checkUserSessionAccess(user.getSessionId(), "/questions", "POST");

Assertions.assertEquals(result, false);
}
Expand Down

0 comments on commit 4c8f249

Please sign in to comment.