Skip to content

Commit

Permalink
create AuthorizedRoles annotation and AuthorizedRolesAspect (#136)
Browse files Browse the repository at this point in the history
* create a model to store user_skill and add remove unused columns in users and skills model

* create a model to store user_skill and add/remove unused columns in users and skills model

* change id to integer

* check if a skill already exists before creating one, make `updated_at` optional in TrackedProperties

* remove unit and integration test and remove skill service & skill service implementation

* add todo

* rename SkillType to SkillTypeEnum

* set logging level debug in application-dev instead of application

* add todo

* remove endorsements list

* add reference to user table in skills modal

* Build api to create a new endorsement

* create api to update an endorsement

* remove unused files

* remove unused code in endorsement controller

* chagne import order

* change the skills project structure to match the new one

* rename exceptions folder to small case exceptions and create user not found and skill already exists exceptions

* create enums folder and move skill type enum to the folder

* rename Conifg to config, move generic response and jwtAuthenticationFilter to utils

* add api to get all endorsements for a skill using skill id in skillsapi

* remove skills package

* fix build error

* move api to create a endorsement to the new folder structure

* add api to update endorsement in apis/endorsements api and remove old Endorsement folder

* move health check api to the api folder & metric service inside the services folder

* fix formatting

* create annotation and aspect to handle authorized roles to an api

* add authorizred roles annotation to skillsapi & endorsementsapi class

* set authorized role for creating a skill to only superuser

* fix formatting
  • Loading branch information
yesyash authored Jul 13, 2024
1 parent dcfdc13 commit 424813a
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.RDS.skilltree.annotations;

import com.RDS.skilltree.User.UserRoleEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthorizedRoles {
UserRoleEnum[] value() default {};
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.RDS.skilltree.apis;

import com.RDS.skilltree.User.UserRoleEnum;
import com.RDS.skilltree.annotations.AuthorizedRoles;
import com.RDS.skilltree.services.EndorsementService;
import com.RDS.skilltree.viewmodels.CreateEndorsementViewModel;
import com.RDS.skilltree.viewmodels.EndorsementViewModel;
Expand All @@ -15,6 +17,7 @@
@RestController
@RequiredArgsConstructor
@RequestMapping("v1/endorsements")
@AuthorizedRoles({UserRoleEnum.USER, UserRoleEnum.SUPERUSER})
public class EndorsementsApi {
private final EndorsementService endorsementService;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.RDS.skilltree.apis;

import com.RDS.skilltree.User.UserRoleEnum;
import com.RDS.skilltree.annotations.AuthorizedRoles;
import com.RDS.skilltree.services.EndorsementService;
import com.RDS.skilltree.services.SkillService;
import com.RDS.skilltree.viewmodels.CreateSkillViewModel;
Expand All @@ -19,6 +21,7 @@
@RestController
@RequiredArgsConstructor
@RequestMapping("v1/skills")
@AuthorizedRoles({UserRoleEnum.USER, UserRoleEnum.SUPERUSER})
public class SkillsApi {
private final SkillService skillService;
private final EndorsementService endorsementService;
Expand All @@ -29,6 +32,7 @@ public ResponseEntity<List<SkillViewModel>> getAll() {
}

@PostMapping
@AuthorizedRoles({UserRoleEnum.SUPERUSER})
public ResponseEntity<SkillViewModel> create(@Valid @RequestBody CreateSkillViewModel skill) {
return ResponseEntity.ok(skillService.create(skill));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.RDS.skilltree.aspects;

import com.RDS.skilltree.User.JwtUserModel;
import com.RDS.skilltree.User.UserRoleEnum;
import com.RDS.skilltree.annotations.AuthorizedRoles;
import com.RDS.skilltree.exceptions.ForbiddenException;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AuthorizedRolesAspect {

@Around("@within(authorizedRoles) || @annotation(authorizedRoles)")
public Object authorize(ProceedingJoinPoint joinPoint, AuthorizedRoles authorizedRoles)
throws Throwable {
JwtUserModel jwtDetails =
(JwtUserModel) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserRoleEnum role = jwtDetails.getRole();

MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Class<?> targetClass = method.getDeclaringClass();

AuthorizedRoles methodAuthorized = method.getAnnotation(AuthorizedRoles.class);
AuthorizedRoles classAuthorized = targetClass.getAnnotation(AuthorizedRoles.class);

UserRoleEnum[] allowedRoles = {};

if (methodAuthorized != null) {
allowedRoles = methodAuthorized.value();
} else if (classAuthorized != null) {
allowedRoles = classAuthorized.value();
} else {
// If no roles are specified, proceed with the method execution
joinPoint.proceed();
}

if (!isAuthorized(role, allowedRoles)) {
throw new ForbiddenException("You're not authorized to make this request");
}

return joinPoint.proceed();
}

private boolean isAuthorized(UserRoleEnum userRole, UserRoleEnum[] allowedRoles) {
for (UserRoleEnum role : allowedRoles) {
if (role.equals(userRole)) {
return true;
}
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.RDS.skilltree.exceptions;

public class ForbiddenException extends RuntimeException {
public ForbiddenException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,10 @@ public ResponseEntity<?> handleEndorsementNotException(
log.error("Exception - Error : {}", ex.getMessage(), ex);
return new ResponseEntity<>(new GenericResponse<>(null, ex.getMessage()), HttpStatus.NOT_FOUND);
}

@ExceptionHandler(ForbiddenException.class)
public ResponseEntity<?> handleForbiddenException(ForbiddenException ex, WebRequest request) {
log.error("Exception - Error : {}", ex.getMessage(), ex);
return new ResponseEntity<>(new GenericResponse<>(null, ex.getMessage()), HttpStatus.FORBIDDEN);
}
}

0 comments on commit 424813a

Please sign in to comment.