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.
Related
On a local Wildfly server I have a simple Java servlet like below:
import javax.servlet.annotation.HttpMethodConstraint;
import javax.servlet.annotation.ServletSecurity;
import javax.servlet.http.HttpServlet;
#ServletSecurity(httpMethodConstraints = { #HttpMethodConstraint(value = "GET", rolesAllowed = { "debug" })})
public class DebugServlet extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try ( PrintWriter out = response.getWriter()) {
/* TODO output your page here. You may use following sample code. */
...
Principal user = request.getUserPrincipal();
out.println("<p>" + (user != null ? user.getName() : "No user") + "</p>");
...
}
}
}
I have set up authentication with Wildfly's Elytron v1.17.2 using OpenID Connect (OIDC) with a third party authentication server. If it matters, it is not a Keycloak server, and changing the auth server isn't an option; using this auth server is a strict business requirement. The auth server has a bunch of users which we want to give access to, but for my particular client_id none of the users have any roles associated with them, and we want to avoid adding roles through the auth server because the process is...tedious at best. Bureaucratic red tape, every time, for every user. Our end goal is to have our own roles in this server's database and we're only going to the 3rd party to handle the login and then verify the login is valid and which user it is.
If I include rolesAllowed = { "debug" } in the HttpMethodConstraint, authentication with the 3rd-party auth server gets triggered and works correctly. But because none of the users have roles associated with them, they don't have the required "debug" role. The processRequest method is never reached and the user gets a "Forbidden" error page.
If I remove or empty the rolesAllowed field of the constraint, authentication with the 3rd-party auth server is not triggered, and there's no UserPrincipal which we can use to identify the user.
I've tried putting a javax.servlet.Filter in to intercept the request before it gets to my Servlet, but if the "debug" role is required then the filter doesn't get reached either. I had hoped to intercept the request after the user authenticates and then add roles to the user, or a session variable, or something which my servlet would then check for permission to do various actions.
I've tried a few other combinations which have not triggered authentication:
#ServletSecurity(httpMethodConstraints = { #HttpMethodConstraint(value = "GET", emptyRoleSemantic = ServletSecurity.EmptyRoleSemantic.PERMIT)})
and
#ServletSecurity(httpMethodConstraints = { #HttpMethodConstraint(value = "GET", transportGuarantee = ServletSecurity.TransportGuarantee.CONFIDENTIAL)})
No luck.
Is there a way I can trigger 3rd-party authentication, and get a UserPrincipal with the authenticated user's username/user id, without requiring a specific role? -OR- Is there a way I can add roles to the authenticated user after authenticating but before being blocked by the HttpMethodConstraint?
The reason your custom filter approach will not work is because the elytron security framework handles this well before your filter chain is invoked. You might try custom role mapper within elytron security as explained here (Section 3.2.9) and here to add some predefined roles.
RoleMapper - After the roles have been decoded for an identity further
mapping can be applied, this could be as simple at normalising the
format of the names through to adding or removing specific role names.
You would obviously need to configure the elytron subsystem to use your custom role mapper. You can take a look at an example configuration for regex-role-mapper here ( in your case you need a custom RoleMapper instead of regex-role-mapper)
I believe elytrons role mapping is the way to go. You could configure a Regex mapper to map every role to one static role. Or use the group-decoder-mapper to convert group names into roles.
See for example: https://wildfly-security.github.io/wildfly-elytron/blog/regex-role-mapper/
I am developing a website using Spring Boot 1.5.7 as back-end and Angular 2 as front-end.
I am a newbie on both technologies, and it's the very first time I try to develop a website. So I am a bit confused on many things.
I have implemented user authentication through JWT.
When the user logins through credentials, the backend verifies them and then creates a JWT and returns it to the frontend: the token is added to the header this way:
Authorization - Bearer <jwt token>
In the frontend I check out if that key is in the post response. If it is there, I add it along with the username to the localStorage.
private authUrl = 'http://localhost:8080/login';
private headers = new Headers({
'Content-Type': 'application/json',
'Accept': 'application/json'
});
constructor(private http: Http) { }
login(username: string, password: string): Observable<void> {
let loginRequest = JSON.stringify({ username: username, password: password });
return this.http.post(this.authUrl, loginRequest, { headers: this.headers })
.map((response: Response) => {
let token = response.headers.get('Authorization');
// If token is not null, empty or undefined.
if (token) {
localStorage.setItem('jwt', JSON.stringify({ username: username, token: token }));
}
});
}
When the user is logged in, everytime he accessed a protected resource, a token will be retrieved from the localStorage and sent back to the backend for validation.
The whole thing works. JWT are immune to CSRF, so I can disable that in the back-end,
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
...
but I have read (for instance, here) that there are vulnerabilities when using localStorage.
In particular the localStorage is accessible through JavaScript on the same domain, exposing to XSS attacks.
To resolve it seems I could use a JWT Cookie. As written in the link before, I could set the HttpOnly cookie flag to avoid cookies to be accessed through JavaScript.
But, with cookies I am now vulnerable to CRSF attacks.
Now, here, I have read Angular 2+ provides built-in, enabled by default, anti XSS.
So the question is. I should use localStorage and just use the embedded Angular 2 anti XSS feature, or is that not enough and then I should store JWTs on cookies to get protection against XSS attacks and then implement on top of it some kind of CRSF protection backend side using Spring Boot configuration?
Thank you
EDIT: the website is a sort of shopping cart. The user can view almost all
pages, but to pay he needs to log in.
Aniruddha Das approach is fine but client application will lost the token if user will refresh the browser because DOM will be reloaded with browser refresh and all memory data including token will be lost.
Now come back to your approach-
Local storage - CSRF attack is not possible using this approach and application will be stateless but it is prone to XSS attack. By default Angular do the output encoding to prevent the XSS attack but risk is still there with server side Angular template. To mitigate the XSS attack, you can reduce the token expiry time and encrypt it, if there is some sensitive information.
Cookie approach - HTTP cookie will mitigate the XSS attack but you have to implement the CSRF protection. You have to use the API gateway pattern to make the application stateless.
Both approach have prons/cons and you have to select depending on your application. If your application is related to financial domain then I would suggest cookie based approach.
In angular you can hold your token in service and use it when ever it required. Like pojo in java in angular you can create a angular service with getter and setter to hold the token. Provide that service to the module and it will available in all component and directives.
The token will be in memory while the application is open in the browser and will be be stored in the browser.
I would say use a observable/Subject type variable so that it will wait until the token is extracted from server and use that to do stuffs.
Recently I have upgrade my all project API's like Spring, Spring Security, Hibernate, Maven, Java. Before upgrade I was using Spring 3 and Spring Security 2.
Now I am using Spring 4 and Spring Security 4 in my project and I have also used cas authentication for login.
When user logged in my application, based on the initial requested URL I want to set target URL of user. Before upgrade it was working fine.
I was using this SPRING_SECURITY_SAVED_REQUEST_KEY to get initial request URL.
Now I am using -
savedRequest = new HttpSessionRequestCache().getRequest(request, response);
to get initial request but it always return null.
Is there any way to get initial request of user after login?
you can use SavedRequestAwareAuthenticationSuccessHandler
Here is how I used the SavedRequestAwareAuthenticationSuccessHandler.
In my case I had an authorization server at localhost:8081 and the secured UI at localhost:8083/app.
In the Authorization server I created the following class:
#Component
public class AuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
setDefaultTargetUrl("http://localhost:8083/app");
super.onAuthenticationSuccess(request, response, authentication);
}
}
In my case there were 3 scenarios of user logging in:
User navigates to http://localhost:8081/login
User navigates to http://localhost:8083/app
User navigates to any secured url within the app like http://localhost:8083/app/files
The class above covers every one of these scenarios by redirecting the user to the original url or if the user choose to login via http://localhost:8081/login, it redirects them to the default target url which is http://localhost:8083/app.
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 have a working JavaEE 6 web application on Glassfish, this application already has a JSF frontend and has its authentication mechanism((Using CDI and annotation based security) So there is a login screen, user enters username password, press login button and Java EE authentication process begins.
Now I want to "also" expose some of my service classes as a REST service (I will use Jersey probably), so it can also be reached from a mobile device. But what worries me is the login part.
I will use the exact same existing authentication But now I want my application will get this credentials from a Rest Request but not from the login screen. And then continue using the existing validation methods which already exists(check username password from DB,,etc)
I kinda got lost how can I do this, I think I need to use one of these filters to intercept the request and get the username password but not sure how and which one? Or I dont need anything like this?
You can protect the REST service the same way you protect the REST service, for example:
#Path("/foo")
#RolesAllowed({"admin", "customer"})
public class Foo {
#GET
#Produces("text/plain")
#RolesAllows("admin")
public void adminOnly() {}
public void adminOrCustomer() {}
}
I guess you already have roles and mappings for them so just use the same roles you got, the application server will take care of the rest.