1212
1313import java .util .List ;
1414
15+ /**
16+ * Validates whether a user is authorized to access a particular resource based on
17+ * their assigned permissions and namespaces.
18+ *
19+ * This validator is active only when the 'secure' profile is enabled.
20+ */
1521@ ApplicationScoped
1622@ IfBuildProfile ("secure" )
1723public class UserAccessValidator {
1824
1925 private static final Logger log = LoggerFactory .getLogger (UserAccessValidator .class );
2026 private final UserAccessStore userAccessStore ;
2127
28+ /**
29+ * Constructs a new UserAccessValidator with the provided UserAccessStore.
30+ *
31+ * @param userAccessStore the store used to retrieve user access permissions
32+ */
2233 public UserAccessValidator (UserAccessStore userAccessStore ) {
2334 this .userAccessStore = userAccessStore ;
2435 }
2536
37+ /**
38+ * Validates whether a user has sufficient access rights to perform an action on a given resource.
39+ * If validation fails, a {@link ForbiddenException} is thrown.
40+ *
41+ * @param userRequestAttributes the request attributes including username, HTTP method, namespace, and path
42+ * @throws ForbiddenException if the user is not authorized
43+ */
2644 public void validate (UserRequestAttributes userRequestAttributes ) {
27-
2845 String action = mapHttpMethodToPermission (userRequestAttributes .requestMethod ());
2946 String requestPath = userRequestAttributes .path ();
3047
@@ -35,6 +52,7 @@ public void validate(UserRequestAttributes userRequestAttributes) {
3552
3653 try {
3754 List <UserAccess > userAccesses = userAccessStore .getUserAccessForUsername (userRequestAttributes .username ());
55+
3856 boolean authorized = userAccesses .stream ().anyMatch (userAccess -> {
3957 boolean resourceMatches = (UserAccess .ResourceType .all == userAccess .getResourceType ())
4058 || requestPath .contains (userAccess .getResourceType ().name ());
@@ -45,35 +63,53 @@ public void validate(UserRequestAttributes userRequestAttributes) {
4563 });
4664
4765 if (!authorized ) {
48- log .warn ("Access denied for user [{}] to path [{}] with action [{}]" , userRequestAttributes .username (),
49- userRequestAttributes .path (),
50- action );
66+ log .warn ("Access denied for user [{}] to path [{}] with action [{}]" ,
67+ userRequestAttributes .username (), userRequestAttributes .path (), action );
5168 throw new ForbiddenException ("Access denied." );
5269 }
5370
5471 } catch (UserAccessNotFoundException ex ) {
55- log .error ("No access permissions assigned to the user: [{}]" , userRequestAttributes .username (), ex . getMessage () );
72+ log .error ("No access permissions assigned to the user: [{}]" , userRequestAttributes .username (), ex );
5673 throw new ForbiddenException ("Access denied." );
5774 }
5875 }
5976
60- //TODO: How to protect GET - /calm/namespaces endpoint by maintaining namespace specific user grants.
77+ /**
78+ * Checks whether the request targets the default-accessible endpoint.
79+ *
80+ * @param userRequestAttributes the attributes of the incoming user request
81+ * @return true if the endpoint is accessible by default, false otherwise
82+ */
6183 private boolean isDefaultAccessibleResource (UserRequestAttributes userRequestAttributes ) {
84+ //TODO: How to protect GET - /calm/namespaces endpoint, by maintaining namespace specific user grants.
6285 return "/calm/namespaces" .equals (userRequestAttributes .path ()) &&
6386 "get" .equalsIgnoreCase (userRequestAttributes .requestMethod ().toLowerCase ());
6487 }
6588
89+ /**
90+ * Maps HTTP methods to access permissions.
91+ *
92+ * @param method the HTTP method
93+ * @return "write" for modifying methods, "read" otherwise
94+ */
6695 private String mapHttpMethodToPermission (String method ) {
6796 return switch (method ) {
6897 case "POST" , "PUT" , "PATCH" , "DELETE" -> "write" ;
6998 default -> "read" ;
7099 };
71100 }
72101
102+ /**
103+ * Checks whether the user's permission level allows the requested action.
104+ *
105+ * @param userPermission the user's assigned permission
106+ * @param requestedAction the action the user is attempting to perform
107+ * @return true if the permission is sufficient, false otherwise
108+ */
73109 private boolean permissionAllows (UserAccess .Permission userPermission , String requestedAction ) {
74110 return switch (userPermission ) {
75111 case write -> requestedAction .equals ("write" ) || requestedAction .equals ("read" );
76112 case read -> requestedAction .equals ("read" );
77113 };
78114 }
79- }
115+ }
0 commit comments