Basic authentication in REST-application

16,758

If I encrypt (NOT encode) password in client when user is signing up and transfer it under the SSL/HTTPS, is this secure and good way to implement this?

Most probably you should simply pass the password in plain text over SSL/HTTPS.

All communication in SSL/HTTPS is encrypted, so it's probably not a good idea to encrypt the password as well unless you need to ensure the web server (technically the HTTPS terminator) cannot see the password.

If I use REST-service without client, it is always open, WHY? No BASIC-authentication? Have I understood something wrong with those url-patterns?

Not sure I understand the question. However BASIC auth is not a good pattern for authentication in REST because it is passing the password in plain text.

IF I get this working how to test that, because now if I authenticate once, I am authorised always? Is it possible to "log out" programatically inside the REST-service or in generally how to implement Log out?

In Basic Auth, the username and password are passed by the client in every HTTP request. If the credentials are not passed by the client, then the server rejects the request. As such there is no concept of session.

However, as far as the Java EE server is concerned, the login creates a user session and future requests by the same user will use the same session. If you so configure it, this session will time out.

If logging out is important (i.e. control user sessions), then you have to create a servlet (/logout) for this which invalidates the HTTP session.

The standard Java security model works as follows: When the user logs in to a security realm, the Java EE server stores a secure cookie in your browser. The browser sends this cookie back to the Java EE server in each request to the same realm. The Java EE server checks for this cookie in every request and uses it to identify the user, connecting the request to the user's session.

So you probably want to do have the REST service in the same security realm as the web application, so the browser and server work seamlessly.

When using Authorization in header with mandatory base64-encoded username:password do I have to encode my username and password to DB as well? I tried that and added Encoding (allowed values are Hex and Base64) to jdbcRealm to Glassfish and it seems that password is enough, but what happens when both are encoded in client?

No, don't encode the username or password - this is all handled deep within the browser and Glassfish. If you encode in the client, the client will encode the encoding and the server will reject the password.


Could you tell me if is it possible to use j_security_check from html5-page with javaScript or am I in problems again :) I have made couple of Primefaces + jsf-application where I used FORM-auth and there wasn't any problem, but this has been totally disaster case for me.

You should be able to get this working comfortably with j_security_check assuming that the RESTful services stay in the same domain and security realm (then logging on to the web application will allow the browser to send the correct cookie to the REST URIs).

Do note, however, that other applications will have difficulty accessing the REST services. Basically, they will have to log in via the j_security_check and then maintain the cookies sent by Glassfish. If you do need other applications to access these services programmatically, then you will need another solution:

  1. You can set up the security realm to allow different authenticators to be 'sufficient'; set up HTTP BASIC Auth as well and make sure that none are marked 'necessary'
  2. Deploy the RESTful services twice, the other being a different URI. If you want to use HTTP BASIC Auth, this might be a SSL/HTTPS end point to ensure the passwords are handled securely
Share:
16,758

Related videos on Youtube

Sami
Author by

Sami

Trying to code here and there with Angular, React, Java, Vaadin...

Updated on September 14, 2022

Comments

  • Sami
    Sami over 1 year

    Environment:

    • JAVA
    • Glassfish
    • REST-services in different machine
    • HTML5-client with AJAX and JQuery
    • Jersey

    This is what I have implemented so far:

    HTML5-client

    $('#btnSignIn').click(function () {
        var username = $("#username").val();
        var password = $("#password").val();
    
        function make_base_auth(user, password) {
            var tok = user + ':' + password;
    
            var final = "Basic " + $.base64.encode(tok);
            console.log("FINAL---->" + final);
            alert("FINAL---->" + final);
    
            return final;
        }
    
        $.ajax({
            type: "GET",
            contentType: "application/json",
            url: "http://localhost:8080/SesameService/webresources/users/secured/login",
            crossDomain: true,
            dataType: "text",
            async: false,
            data: {},
            beforeSend: function (xhr) {
                xhr.setRequestHeader('authorization', make_base_auth(username, password));
            },
            success: function () {
                alert('Thanks for your signin in! ');
    
            },
            error: function (jqXHR, textStatus, errorThrown) {
                console.log(textStatus, errorThrown);
                alert(' Error in signIn-process!! ' + textStatus);
            }
        });
    });
    

    SERVER

    In Security, I haven't got Security Manager enabled, it is disabled!

    I have configured BASIC-authentication to Glassfish and my web.xml looks like that:

    <servlet-mapping>
        <servlet-name>ServletAdaptor</servlet-name>
        <url-pattern>/webresources/*</url-pattern>
    </servlet-mapping>
    
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>REST Protected resources</web-resource-name>
            <description/>
            <url-pattern>/users/*</url-pattern>
            
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
            <role-name>customer</role-name>
            <role-name>user</role-name>
        </auth-constraint>
    </security-constraint>
    
    
    
    <login-config>
            <auth-method>BASIC</auth-method>
            <realm-name>jdbcRealm</realm-name>
        </login-config>
        <security-role>
            <role-name>admin</role-name>
        </security-role>
        <security-role>
            <role-name>user</role-name>
        </security-role>
        <security-role>
            <description/>
            <role-name>customer</role-name>
        </security-role>
    

    GLASSFISH

    enter image description here

    LOG

    FINE: [Web-Security] Setting Policy Context ID: old = null ctxID = SesameService/SesameService
    FINE: [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/webresources/users/secured/login" "GET")
    FINE: [Web-Security] hasUserDataPermission isGranted: true
    FINE: [Web-Security] Policy Context ID was: SesameService/SesameService
    FINE: [Web-Security] hasResource isGranted: true
    FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/webresources/users/secured/login" "GET")
    

    QUESTION:

    1. If I encrypt (NOT encode) password in client when user is signing up and transfer it under the SSL/HTTPS, is this secure and good way to implement this?

    2. If I use REST-service without client, it is always open, WHY? No BASIC-authentication? Have I understood something wrong with those url-patterns?

       http://localhost:8080/SesameService/webresources/users/secured/login
      
    3. IF I get this working how to test that, because now if I authenticate once, I am authorised always? Is it possible to "log out" programatically inside the REST-service or in generally how to implement Log out?

    4. When using Authorization in header with mandatory base64-encoded username:password do I have to encode my username and password to DB as well? I tried that and added Encoding (allowed values are Hex and Base64) to jdbcRealm to Glassfish and it seems that password is enough, but what happens when both are encoded in client?

    UPDATE: I changed web.xml and now BASIC-authentication is working when calling REST-service straight in browser :http://localhost:8080/SesameService/users/secured/login

    Changes:

    • I enabled security manager in Glassfish
    • I changed url-pattern
        <servlet-mapping>
            <servlet-name>ServletAdaptor</servlet-name>
            <url-pattern>/*</url-pattern>----> I took webresources off. It was generated by Netbeans
        </servlet-mapping>
    
    • I changed the url to service to this: http://localhost:8080/SesameService/users/secured/login

    Now I get a HTTP/1.1 401 Unauthorized when trying to authenticate from HTML5-client.

    Request headers:

    Origin: http://localhost:8383
    Host:localhost:8080
    Connection:keep-alive
    Access-Control-Request-Method:GET
    Access-Control-Request-Headers:authorization,content-type
    

    Response:

    x-powered-by:Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 3.1.2.2 Java/Oracle Corporation/1.7)
    WWW-Authenticate:Basic realm="jdbcRealm"
    Server:GlassFish Server Open Source Edition 3.1.2.2
    Pragma:No-cache
    Expires:Thu, 01 Jan 1970 02:00:00 EET
    Date:Sat, 13 Apr 2013 15:25:06 GMT
    Content-Type:text/html
    Content-Length:1073
    Cache-Control:no-cache
    

    UPDATE 2

    When I try to authenticate with JavaScript + Authorization-header I got 401 error and that in the log:

    FINE: [Web-Security] Setting Policy Context ID: old = null ctxID = SesameService/SesameService
    FINE: [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/users/secured/login" "OPTIONS")
    FINE: [Web-Security] hasUserDataPermission isGranted: true---->!!!!!!!!!!!!!
    FINE: [Web-Security] Policy Context ID was: SesameService/SesameService
    FINE: [Web-Security] Codesource with Web URL: file:/SesameService/SesameService
    FINE: [Web-Security] Checking Web Permission with Principals : null------->!!!!!!!
    FINE: [Web-Security] Web Permission = ("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS")
    FINEST: JACC Policy Provider: PolicyWrapper.implies, context (SesameService/SesameService)- result was(false) permission (("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS"))
    FINE: [Web-Security] hasResource isGranted: false------->!!!!!!!!!
    FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS")
    FINEST: JACC Policy Provider: PolicyWrapper.getPermissions(cs), context (null) codesource ((null <no signer certificates>)) permissions: java.security.Permissions@5d4de3b0 (
    

    UPDATE 3 I can't be the first and only person who is trying to authenticate using BASIC in cross domain case. I changed my cross origin filters like that:

    response.getHttpHeaders().putSingle("Access-Control-Allow-Headers", "Authorization");
    

    NO 401 error anymore but still error in JavaScript. IN Glassfish log:

    FINEST: JACC Policy Provider:
    getPolicy (SesameService/SesameService) is NOT in service----->!!!!!!!!
    FINE: JACC Policy Provider: file arrival check type: granted  arrived: false exists: false lastModified: 0 storedTime: 1365968416000 state: deleted SesameService/SesameService
    FINE: JACC Policy Provider: file arrival check type: excluded  arrived: false exists: false lastModified: 0 storedTime: 0 state: deleted SesameService/SesameService
    FINE: TM: getTransaction: tx=null, tm=null
    FINE: TM: componentDestroyedorg.apache.catalina.servlets.DefaultServlet@227fe9a8
    FINE: TM: resourceTable before: 0
    FINE: TM: resourceTable after: 0
    

    BTW, because I have never get this work, does this work same way than calling the REST-service direct in its own domain. So, First client requests, server requests and username-password window opens, then client request and server authenticate and response the page? I am trying to get it: Request with Authorization header in it, response from server with result from the rest service and that's it. Any idea how to secure REST-services? Easier than that? This is impossible.

    UPDATE 4

    I just tried to move my HTML5-client to under java web-project, just pure html-pages and under same domain and BASIC-authentication is working 100 %. So the reason is because of cross-domain environment.

  • Arjan Tijms
    Arjan Tijms about 11 years
    >When the user logs in to a security realm, the Java EE server stores a secure cookie in your browser - This is not directly the case. A user creates a session with a specific web application on a Java EE server, and for that a cookie is put in the response. Whether a security realm happens to be associated with that web application is largely irrelevant for this session. A secure cookie is only used when so configured in web.xml. Java EE does not detail HOW an auth module should remember an authentication. Before Java EE 7 (JASPIC 1.1) it did not even mention remembering at all.
  • Andrew Alcock
    Andrew Alcock about 11 years
    @ArjanTijms: I hear you; I was attempting to simplify what actually happens (and what in practice happens in JEE 7, 6, 5, ...). The key for Sami is that a session is there on the client.
  • Sami
    Sami about 11 years
    I moved my html5-client code to same project where rest services are under the same domain and it is working like it should. So the cross-domain might be the culprit. This is so annoying case that I might to try implement normal FORM-auth with javascript + j_security_check under the one and only domain. Is it BTW possible to use j_security_check in that case?
  • Andrew Alcock
    Andrew Alcock about 11 years
    @Sami - I'm on my phone right now. Cross-domain is almost certainly the root cause. This is because the server needs to prevent cross-domain script attacks and your REST service will look exactly like this. I'll write some more in a few hours
  • Sami
    Sami about 11 years
    @Andrew Alcock. Thanks! Could you tell me if is it possible to use j_security_check from html5-page with javaScript or am I in problems again :) I have made couple of Primefaces + jsf-application where I used FORM-auth and there wasn't any problem, but this has been totally disaster case for me.
  • Andrew Alcock
    Andrew Alcock about 11 years
    @Sami: I've added an explanation onto my answer