I am porting a REST web application from struts 2 to spring 5 (w/ spring boot). In our Api, we pass three attributes in each request (names are anonymised):
uuid, token, bananaId
In the backend we look for a user in a database with uuid, and check if it has token in it's list of tokens. If it has, the request is authorized and we add bananaId to the user's set of bananas.
I can do checking in each request individually -- and this is how it was implemented in struts. How to make a spring interceptor which would do this for each request (excluding a login action)?
I have successfully configured HandlerInterceptorAdapter, but I'm stuck on what to do next. Which approach is the best in this case?
EDIT: pseudo code of a controller
#RequestMapping("/getFoo")
public GetFooRsponse getFoo(#RequestBody Request request) {
Optional<User> user = getUser(request.getUuid());
if (user.isPresent() && user.get().getGcmTokens().contains(request.getGcmToken())){
user.get().getBanIds().add(request.getbanId());
// handle request
} else {
// unauthorized?
}
}
A solution which would be fine:
#RequestMapping("/getFoo")
#CheckGcmToken
public GetFooRsponse getFoo(#RequestBody UserRequest request) {
// handle request
}
Related
I have a Spring Boot web application that expects all incoming requests to have a cookie with a valid JWT ID token. The ID token holds the email address of the user, which is used to query the database for the User entity. The User entity is then used by multiple services.
Currently, the controllers receive the raw ID token as a parameter, and then passes it down to the services:
#PostMapping()
void foo(#CookieValue String rawIdToken) {
myService.bar(rawIdToken);
}
Then each service is parsing the token and querying the database:
void bar(String rawIdToken) {
// Parse the ID token
IdToken idToken = IdToken.from("RAW_ID_TOKEN");
// Query the database
User user = userRepository.findByEmail(idToken.getEmail());
// Code that requires the User entity..
}
Is there a way to avoid having to do this every time, and instead automatically make the User entity available to all controllers? So that, for example, the sample controller above can become something like that:
#PostMapping()
void foo(User user) {
myService.bar(user);
}
And the service:
void bar(User user) {
// Code that requires the User entity..
}
Please let me know if I am looking at this the wrong way.
You can create a Filter. This Filter gets the User from DB and add it to session as attribute.
Then you can take the User object from session by httpRequest.getAttribute()
Here is about creating filter: https://www.baeldung.com/spring-boot-add-filter
It is about setting ang getting session object: Spring: how to pass objects from filters to controllers
I have a use case in which I have to perform authorization part only. JWT token is getting generated by another service. My service will only consume that token which will have data in it's custom claim. In my spring boot application, I just want to verify that token if it's valid or not before allowing users to access any API. In all answers I can see one Authentication object is created from current Security context. Is there any way in spring in which I don't need to write so much unnecessary code in Custom Filter and just write the logic to parse JWT token and if it is valid, then allow user to API or else send unauthorized response?
Auth0 Java JWT provides few methods to verify JWT token. I want to validate and parse using code like below
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm).withIssuer(issuer).build();
DecodedJWT decoded = verifier.verify(token);
If you want to work with spring security you have to work with those things (filters, authentication object, context, etc.). You have to set an Authentication to be able to access protected resources. It's not complicated at all, you don't have to write "useless" code but just tell spring security what you want to do.
In your case, you just have to provide a custom filter that matches your criterias.
We can imagine something like :
#Component
public class TokenAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) req;
// Here, I get the token from authorization header, change if you get it from anywhere else
String token = httpRequest.getHeader("Authorization");
// here i'm just doing a dummy check. if my token equals "mysupersecrettoken" the authentication is validated
// change this test by yours (using Auth0 etc.)
if ("mysupersecrettoken".equals(token)) {
// dummy authentication object. You can set a real username / credentials / role based on the claims of your token if you want to.
UsernamePasswordAuthenticationToken user = new UsernamePasswordAuthenticationToken("username", "credentials",
Arrays.asList(new SimpleGrantedAuthority("ROLE")));
SecurityContextHolder.getContext().setAuthentication(user);
}
// call next filters, if authentication is not valid, no authentication will be set so user will not be authenticated
chain.doFilter(req, res);
}
}
It's not the best way to work with spring security but it's a kind of "minimal" way to achieve your usecase. You'll probably need to set some security context too but it's not a big thing.
Spring Security ships with out of the box support for JWT authentication, so you would not need to write any code aside from configuration. See OAuth 2.0 Resource Server JWT in the reference docs. You can enable it with the Spring Security DSL using:
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
Note that JWTs can be used outside of OAuth 2.0 with this support, though it may not be obvious at first that this is the case. You can check out the JWT Login sample to see how that is accomplished, but the main takeaway is that you need to provide an #Bean of type JwtDecoder that is created with a public key, such as:
#Bean
JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(this.key).build();
}
Also see this Tanzu Tuesday talk for a deep dive on this subject.
I'm familiar with implementing BasicAuth security in Dropwizard, but only for RESTful endpoints/resources.
I am now experimenting with Dropwizard Views to see if I can use it to be both a web and REST server all in one. The web app will have "public" pages (that are really just static HTML files; "About Us", "Contact Us", etc.) as well as "private" (dynamic) pages, which really form the app. To get to these pages the user must be authenticated (logged in).
So this means I have the need for two distinct DW authentication mechanisms:
A typical DW security mechanism for authenticating REST API clients, which I'm familiar with; and
A way to implement a log in system for authenticating end users for the web app pages/resources
Ideally, I'd like Apache Shiro to handle all auth for my system (REST and web alike), and I see the Dropwizard-Shiro lib, but that seems to only authenticate REST endpoints.
My web login system need to work like so:
A user tries to go to an "authenticated" (private) URL.
A servlet filter (that I create myself and register with the environment) intercepts the request and can tell (perhaps a cookie/session var?) whether the user is authenticated or not.
If the user is authenticated, they are allowed to proceed to their intended URL ("target URL"). Otherwise they are redirected to a login page. When they login a DW resource/controller hands their credentials off to Shiro, who then decides whether the credentials are valid or not.
If the credentials are valid, they get a cookie/session var (?) and are redirected to their target URL. Otherwise they are redirected back to the login page which will now display a failure message.
My main concerns are:
* What should I implement for the cookie/session var that the servlet will check for?; and
* How do I integrate my auth controller (that is, the resource that handles redirection between the login page and the target URL) with Shiro? Is it possible to do this via that Dropwizard-Shiro lib?
My best attempt thus far:
Custom Servlet Filter (registered with environment):
public class AuthFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext) {
Cookie[] cookies = requestContext.getCookies();
boolean authenticated = false;
for(Cookie cookie : cookies) {
// 1. This is my first concern. What is better/more secure
// than what I'm doing here?
if("my_app_auth_cookie".equals(cookie.getName())) {
authenticated = true;
}
}
if(authenticated == false) {
responseContext.sendDirect("/auth/login");
}
}
}
If they are not authenticated they redirect to /auth/login which hits a AuthController (again, registered with the environment as a resource):
#Path("/auth")
#Produces(MediaType.TEXT_HTML)
public class AuthController {
#GET
#Path("/login")
public LoginPageView login() {
// Render some "login.ftl" template as HTML.
}
#POST
#Path("/authenticate")
public ??? authenticate(??? username, ??? password) {
// 2. Somehow send 'username' and 'password' to Shiro...
MyAppUser user = myAppRealm.authenticate(username, password);
// Now what do I do with 'user'?
}
}
When the user submits the form on the login page (which might be a POST to /auth/authenticate) we somehow hand their inputted credentials off to Shiro (again I'd like to use that Dropwizard-Shiro lib since I will likely also be using it for my REST endpoints).
Apache Shiro has its own type of filters which are configured in shiro.ini.
Example:
[urls]
/api/** = noSessionCreation, authcBasic
/views/login = authc
/views/authenticated = authc, user
Configure the authc filter to redirect to a login form page that you implement. Use the filter's form parameters and POST to /views/login.
If you enable the session manager in Jetty, Shiro should create servlet sessions when they log in from the login form page.
Please note that I haven't actually tested this configuration.
I am new to Jersey REST Framework , so please excuse if this is a dumb question .
I am using Tomcat with Hibernate and Jersey REST Webservices.
I have got set of HTML pages in my Web APP
login.html
dealer.html
sales.html
I dont want the User to access the HTML pages directly other than login.html
So to resolve this issue , when submit is pressed , under login.html call
following call is made to the backend
#Path("/webchecklogin")
public class WebLoginCheck {
#Context
private HttpServletResponse response;
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces("application/json")
public String getData(LoginInfo loginInfo ) throws JSONException,ClassNotFoundException, SQLException
{
String ID = loginInfo.getID();
String email = loginInfo.getEmail();
// validate this values with Database and if successfully logged in , stored them in session AND cookies also
}
}
And inside dealer.html and sales.html , on page ready i am calling a service as shown below
var checkcallajax = $.ajax({
type: 'GET',
url: url + '/ORIENT/orn/checkifuserloggedin',
jsonpCallback: 'jsonCallback',
success: function(response) {
}
})
#Path("/checkifuserloggedin")
public class CheckIfUserLoggedIn {
#Context
private HttpServletRequest request;
#GET
#Consumes(MediaType.APPLICATION_JSON)
#Produces("application/json")
public String checkIfUserLoggedIn() throws JSONException,ClassNotFoundException, SQLException
{
// On what basis , should i check wheher the USER is logged or NOT
// I tried storing data with Session and cookies , but i am unable to retrive them here
//return true or false
// based on true or false , i am redireting user to appropiate page
}
}
Could anybody please let me know how to approach this
RestFUL web services are supposed to be stateless, so in theory, you could send the credential with every request, and that would be totally stateless from the "server point of view"
Most will find this cumbersome, resource intensive, and storing credentials on the client is somewhat bad from a security point.
The alternative approach could be that your login method returns a token, that needs to be re-sent (in a header maybe) to the server with every request.
The client must know how to store it (session cookie? on the domain
serving html, if you are in a CORS scenario)
The server must know how to validate the token.
On top of it, the validation of the Token can be done in a JaxRS Filter... before reaching your service entry point. And even better, this filter could add roles to the request context, so you can the use the #RolesAllowed annotation with your services.
I "very personnally" avoid relying on the javax.servlet.Session, as this is fundamentally stateful. But, you should be able to do it, given that the clients stores the jSessionId (other other cookie name) in a session cookie. If it does not work, you might have CORS or other domain specific problem, preventing the client from storing and returning this cookie automatically.
Hope it helps.
I am using #requestbody and #responsebody annotations for my authentication method using Spring MVC. I want to know how can I get and set cookies in spring mvc.. I need to store username and password in my cookie, which I am getting through the requestbody. Also want to know how can I get this set cookie in the browser, the next time the user logs in. Also does the browser sends the cookie automatically with the request body ? To be specific I don't want to go for Spring Security Remember me option. I am new to spring framework so an example code would be highly appreciated.
Ajax Code in JS:
var ajaxOptions = {
type: callType,
url: serviceCompleteUrl,
/* Add if required.
dataType: returnType */
async: false,
success: function(data, status, xhr) {
/*
* TODO: See if this is required
if (xhr.status == 200) {
*/
ajaxSuccess = true;
serviceResponse = data;
/*
}
*/
},
in the service I am just returning the object which will be mapped onto the serviceResponse and could be used by JS..
Sample code for service :
#RequestMapping("/login")
public #ResponseBody LoginObject Login(#RequestBody LoginParameter request)
{
/* Code */
return LoginObject;
}
This is how I am returning the object from the service, which is then catched by the serviceresponse in js..
Never store passwords (even encrypted) in Cookies. To implement the Remember me functionality you desire, you follow this answer
Update:
You need the logic for saving data in cookies on JS side. After the call to the service returns LoginObject, use some JS or jQuery code (like document.cookie="key=" + value;) to store data in cookies.