How REST call token can be injected in the RunContext as Principal [message #1841320] |
Wed, 12 May 2021 07:21 |
Seydou Zakou Messages: 44 Registered: May 2020 |
Member |
|
|
Hi all,
We need to provide some REST api for our Scout application. We are using a token based authentication. Token is got by first authenticating the user (login, password) and then generated a token to be used in the next calls. So getting detail of a user API method is as follow:
@GET
@Path("get/{id}")
@Produces(MediaType.APPLICATION_JSON)
public UserEntityDo getUserDetail(@HeaderParam("token") String token, @PathParam("id") String id) {
// Check token validity and return corresponding user name if any
String username = checkToken(token);
if (username == null) {
Response.status(Response.Status.FORBIDDEN).build();
}
Subject subject = new Subject();
subject.getPrincipals().add(new SimplePrincipal(username));
subject.setReadOnly();
RunContext runContext = RunContexts.empty().withSubject(subject);
Map<String, Object> data = runContext.call(new Callable<Map<String, Object>>() {
@Override
public Map<String, Object> call() throws Exception {
return BEANS.get(IUserService.class).getData(UUID.fromString(id));
}
});
// Build user entity data
UserEntityDo user = BEANS.get(UserEntityDo.class).withLogin((String) data.get("login"))
.withLastLoginDate((Date) data.get("lastLoginDate").withFirstName((String) data.get("firstName").withLastName((String) data.get("lastName"));
return user;
}
The code work perfectly but we have to use the portion of code from //Check... till //Build... in all our method.
I'am thinking about putting this code within a ServletFilter that will inject the user principal in the RunContext based on the header token, but have no idea how to implement it.
Does anyone have an idea ?
Thanks in advance.
[Updated on: Wed, 12 May 2021 07:46] Report message to a moderator
|
|
|
Re: How REST call token can be injected in the RunContext as Principal [message #1841325 is a reply to message #1841320] |
Wed, 12 May 2021 09:49 |
|
Seydou Zakou wrote on Wed, 12 May 2021 07:21I'am thinking about putting this code within a ServletFilter that will inject the user principal in the RunContext based on the header token, but have no idea how to implement it.
Yes, I think that's the correct approach. The only downside is that in a ServletFilter you don't get the nice @HeaderParam convenience from JAX-RS. Instead you have to extract it yourself from the HTTP request. Something like this (untested):
import java.io.IOException;
import javax.security.auth.Subject;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.scout.rt.platform.context.RunContexts;
import org.eclipse.scout.rt.platform.security.SimplePrincipal;
public class TokenFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String token = getToken(req);
String username = checkToken(token);
if (username == null) {
resp.sendError(HttpServletResponse.SC_FORBIDDEN);
} else {
Subject subject = createSubject(username);
RunContexts.copyCurrent(true)
.withSubject(subject)
.run(() -> chain.doFilter(request, response));
}
}
protected String getToken(HttpServletRequest req) {
// Extract token from HTTP request
return req.getHeader("token");
}
protected String checkToken(String token) {
// Convert token to username
return ...;
}
protected Subject createSubject(String username) {
// Create subject from username
Subject subject = new Subject();
subject.getPrincipals().add(new SimplePrincipal(username));
subject.setReadOnly();
return subject;
}
@Override
public void destroy() {
}
}
Regards,
Beat
|
|
|
|
Powered by
FUDForum. Page generated in 0.03407 seconds