For general use, please check the main Plume Admin documentation
For general use WebSessionAdmin is provided, but you might want to add other fields in your JWT token. This guide describe how to handle your own JWT token based session and how to secure your API: this way API endpoints you configure will require a valid JWT session in order to be accessed.
You'll need an object that implement both WebSessionPermission and WebSessionFingerprint. For example:
@Getter
@Setter
@Accessors(chain = true)
public class MyWebSession implements WebSessionPermission, WebSessionFingerprint {
private Long userId;
private String userName;
private Set<String> permissions;
private String hashedFingerprint;
}
If you don't need session permissions and/or fingerprints, you'll need to implement your own RequestPermissionProvider, and specify that you web session won't extend WebSessionPermission and/or WebSessionFingerprint.
This object will contains at least your jwt token:
public class LoginBean {
@JsonSerialize(using = ToStringSerializer.class)
private String token;
public LoginBean(String token) {
this.token = token;
}
}
For this step, you should have bind the JWT Signer and have a JWT secret like detailed in the main documentation. You may want to add a time provider to specify a token duration.
bind(TimeProvider.class).to(SystemTimeProvider.class);
Converting your data to the token object:
private MyWebSession convertToJWTSession(User user) {
return new MyWebSession().setUserId(user.getId()).setUserName(user.getEmail()).setPermissions(user.getPermissions());
}
And your token object to your jwt token string
String jwtToken = webSessionSigner.serializeSession(
convertToJWTSession(user),
timeProvider.currentTime() + TOKEN_EXPIRY_DURATION.toMillis()
);
By default you might be using AdminSecurityFeature, but this is tied to both WebSessionAdmin and RestrictToAdmin
You'll need to add a class that implements DynamicFeature
. You need to indicate what is the expected object when the token is parsed and to what annotation is security will be linked to.
In our example we will use RestrictTo
as the annotation, then we would have:
@Singleton
public class SecurityFeature implements DynamicFeature {
private final PermissionFeature<RestrictTo> permissionFeature;
@Inject
public SecurityFeature(WebSessionSigner webSessionSigner, AdminSecurityConfigurationService configurationService) {
this.permissionFeature = new PermissionFeature<>(
new WebSessionRequestPermissionProvider<>(
webSessionSigner,
MyWebSession.class,
configurationService.sessionUseFingerprintCookie()
),
RestrictTo.class,
RestrictTo::value
);
}
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
permissionFeature.configure(resourceInfo, context);
}
}
In your Jersey config file make sure the annotation is registered and add your new SecurityFeature
You'll need to add any custom Annotation.
config.register(RequireExplicitAccessControlFeature.accessControlAnnotations(RestrictTo.class, PublicApi.class));
config.register(SecurityFeature.class);
You can now secure your webservices using the RestrictTo
annotation and the permission string that will be verified to be in your token:
@RestrictTo(JwtPermission.BASIC_RIGHT)
public class UtilisateurWs {
[...]
}
Final step is to provide a Factory
that will be used to create back your MyWebSession
object from the received request. Below is the corresponding example:
public class MyWebSessionFactory implements Factory<MyWebSession> {
private final ContainerRequestContext context;
private final WebSessionSigner webSessionSigner;
private final boolean verifyCookieFingerprint;
@Inject
public MyWebSessionFactory(ContainerRequestContext context, WebSessionSigner sessionSigner,
AdminSecurityConfigurationService configurationService) {
this.context = context;
this.webSessionSigner = sessionSigner;
this.verifyCookieFingerprint = configurationService.sessionUseFingerprintCookie();
}
@Override
public MyWebSession provide() {
return JerseySessionParser.currentSessionInformation(context, webSessionSigner, MyWebSession.class, verifyCookieFingerprint);
}
@Override
public void dispose(JwtPermission permission) {
// unused
}
}
and register it in Jersey:
config.register(new AbstractBinder() {
@Override
protected void configure() {
bindFactory(MyWebSessionFactory.class).to(WebSessionPermission.class).in(RequestScoped.class);
bindFactory(MyWebSessionFactory.class).to(MyWebSession.class).in(RequestScoped.class);
}
});
You might want to disable fingerprint on your development environnement in case it's not secured (HTTP and not HTTPS)
admin.session.fingerprint-cookie-https-only = false
admin.session.use-fingerprint-cookie = false
You simply need to add the object in your webservice method:
@GET
@Path("/me")
public UserBean findMe(@Context MyWebSession securityContext) {
return userService.findUserDetailByEmail(securityContext.getUserName());
}