Authorization pattern
What is the Authorization pattern?
This security pattern is used to implement an authorization mechanism. A class diagram of the pattern is given below.
PAMELA implementation of the pattern is build around three entities: Subjects, Resources and Permission Checkers. Subjects are the entities which want to access the Resource. Resources need to be secured. Each of these have a Permission Checker which can say whether an access to the Resource is authorized based on the Resource Identifier and the Subject Identifier trying to access the resource. The authorization mechanism is thus the dynamic check to the of the Permission Checker of a Resource every time a Subject tries to access it.
How to use the pattern?
Subject and Resource entities
- Identify the Subject class. This is the class whose instance will need to be authorized to access resources. This class should be annotated with
@ModelEntity
(to let the PAMELA framework know that it is part of your model) and@AuthorizationSubject(patternID = <patternID>)
(to declare it as a Subject for the Authorization pattern). The<patternID
is a String identifying the pattern in you model. Note that the same<patternID>
should be used for all annotations of the pattern. You could, for instance, have the following code:
@ModelEntity
@AuthorizationSubject(patternID = "Authorization pattern 1")
public class mySubject {
...
}
- Identify the Subject Identifier getter(s). They will be used to determine whether a Subject instance is authorized to access a Resource instance. Each of these getters should be annotated with
@SubjectID(patternID = <patternID>, paramID = <paramID>
). The<paramID>
is a String identifying getter. You could, for instance, have the following code:
@ModelEntity
@AuthorizationSubject(patternID = "Authorization pattern 1")
public class mySubject {
@SubjectID(patternID = "Authorization pattern 1", paramID = "username")
public String getUsername(){
...
}
@SubjectID(patternID = "Authorization pattern 1", paramID = "password")
public int getPasswordHash(){
...
}
}
- Similarly, identify the Resource class and annotate it with
@ModelEntity
and@ProtectedResource(patternID = <patternID>)
. The annotate its identifier getters with@ResourceID(patternID = <patternID>, paramID = <paramID>)
. You could, for instance, have the following code:
@ModelEntity
@ProtectedResource(patternID = "Authorization pattern 1")
public class ProtectedFile {
@SubjectID(patternID = "Authorization pattern 1", paramID = "path")
public String getPath(){
...
}
}
- In the Resource class, you should identify the Permission Checker getter. This entity is the one which will check every access to the Resource. You could, for instance have the following code:
@ModelEntity
@ProtectedResource(patternID = "Authorization pattern 1")
public class ProtectedFile {
@SubjectID(patternID = "Authorization pattern 1", paramID = "path")
public String getPath(){
...
}
@PermissionCheckerGetter(patternID = "Authorization pattern 1")
public Permission getPermission(){
...
}
}
- Identify the Resource Access methods. These methods are the one you want to protect. Each of this method should be annotated with
@AccessMethod(patternID = <patternID>, methodID = <methodID>)
. The<methodID>
is a String identifying the Access method. You could for instance have the following code:
@ModelEntity
@ProtectedResource(patternID = "Authorization pattern 1")
public class ProtectedFile {
@SubjectID(patternID = "Authorization pattern 1", paramID = "path")
public String getPath(){
...
}
@PermissionCheckerGetter(patternID = "Authorization pattern 1")
public Permission getPermission(){
...
}
@AccessMethod(patternID = "Authorization pattern 1", methodID = "read")
public String read(int n){
}
@AccessMethod(patternID = "Authorization pattern 1", methodID = "write")
public void write(String s){
...
}
}
- For all Access method identified in the Resource class, you should define an abstract method (or with empty body) in the Subject class with the same annotation. These method should have the same prototype with one difference: They will all have one extra annotated parameter for each Identifier of the Resource class. These parameters should be annotated with the same annotation used for the associated Subject Identifier getter(s) You could, for instance, have the following code:
@ModelEntity
@AuthorizationSubject(patternID = "Authorization pattern 1")
public class mySubject {
@SubjectID(patternID = "Authorization pattern 1", paramID = "username")
public String getUsername(){
...
}
@SubjectID(patternID = "Authorization pattern 1", paramID = "password")
public int getPasswordHash(){
...
}
@AccessMethod(patternID = "Authorization pattern 1", methodID = "read")
public String readFile(int n, @SubjectID("Authorization pattern 1", paramID = "path") String path){
}
@AccessMethod(patternID = "Authorization pattern 1", methodID = "write")
public void write(String s, @SubjectID("Authorization pattern 1", paramID = "path") String path){
...
}
}
- Identify the Permission Checker class and annotate it with
@ModelEntity
and@AuthorizationChecker(patternID = <patternID>)
. You could, for instance, have the following code:
@ModelEntity
@AuthorizationChecker(patternID = "Authorization pattern 1")
public class Permission {
...
}
- Finally you need to annotate the Check method with
@CheckAccess(patternID = <patternID>)
. This method have several parameters which all need to be annotated:You could, for instance, have the following code:+ _Subject identifier(s)_ and _Resource Identifier(s)_. Every time a _Subject access method_ will be called, the _Subject and Resource identifiers_ will be given to this method. They are annotated with the same annotation used to declare the associated getters.
+ _MethodID_. This argument is a String and identify the access method that is currently processed by the pattern. This parameter is annotated with `@MethodID(patternID = <patternID>)`
@ModelEntity
@AuthorizationChecker(patternID = "Authorization pattern 1")
public class Permission {
@CheckAccess(patternID = "Authorization pattern 1")
public boolean check(
@SubjectID(patternID = "Authorization pattern 1", paramID = "username") String username,
@SubjectID(patternID = "Authorization pattern 1", paramID = "password") int password,
@ResourceID(patternID = "Authorization pattern 1", paramID = "path") String path,
@MethodID(patternID = "Authorization pattern 1") String accessType
)
{
...
}
}
How does it work?
Once all three classes are correctly annotated, the pattern will ensure that every call to a Subject access method is handled as followed:
The Resource whose id is given as a parameter is retrieved by the pattern. That way, the Subjects do not need to have any references to Resource.
The Permission Checker of the said Resource is retrieved. Its Check method is called with the right parameters.
If the Check call returns
true
, then the correct Resource access method is called and the result of the call is returned.If the Check call returns
false
, an exception is thrown and no Resource method is called.
In addition, the pattern will ensure that the Subject and Resource Identifier do not change throughout runtime. It will also ensure that the references to a Permission Checker of a Resource does not change either.
Extra: You can annotated has many Subject methods as you want with @RequiresAuthentication(<patternID>
. This annotation will ensure that every call to the method will first trigger the authentication process (call to the Subject authenticate method).