6
votes

There many ways to get a good security for REST(easy) services. I tried already. In this case only is a Basic Authentication needed. So, not based on login, RequestFilters, etc. Please focus on this example.

While adding security to one RestEasy 'post' method, I keep on getting 401 exceptions. How can I get secure access to the 'post'? I used the the Authenticator code of Adam Bien / Atjem König.

Without the security settings in the web.xml I get normal access, so that part of the code is working fine. I don't need/want any login-screen in between.

Tomcat users: conf/tomcat-users.xml:

 <user username="wineuser" password="winepass" roles="winer"/>

Web.xml file:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>wine secret</web-resource-name>
        <url-pattern>/rest/wines/secret</url-pattern>
        <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
        <role-name>winer</role-name>
    </auth-constraint>
</security-constraint>
<login-config>
    <auth-method>BASIC</auth-method>
</login-config>
<security-role>
    <role-name>winer</role-name>
</security-role>

Application class:

@ApplicationPath("/rest")
public class RestEasyWineServices extends Application {
}

Authenticator utils:

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.xml.bind.DatatypeConverter;

public class Authenticator implements ClientRequestFilter {
    private final String user;
    private final String password;
    public Authenticator(String user, String password) {
        this.user = user;
        this.password = password;
    }
    public void filter(ClientRequestContext requestContext) throws IOException {
        MultivaluedMap<String, Object> headers = requestContext.getHeaders();
        final String basicAuthentication = getBasicAuthentication();
        headers.add("Authorization", basicAuthentication);
    }
    private String getBasicAuthentication() {
        String token = this.user + ":" + this.password;
        try {
            return "Basic " +
                 DatatypeConverter.printBase64Binary(token.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException ex) {
            throw new IllegalStateException("Cannot encode with UTF-8", ex);
        }
    }
}

Resource class and method:

@Path("/wines")
public class WineResource {
    ...
    @POST @Path("secret")
    @Produces({ MediaType.APPLICATION_JSON })
    @Consumes({ MediaType.APPLICATION_JSON})
    public Wine echoPostWineSecret( Wine inputWine2) {
        System.out.println( "Server: **SECRET** post (" + inputWine2 + ")");
        inputWine2 = dao.create(inputWine2);
        return inputWine2;
    }
}

Client class:

Client clientSecret = ClientBuilder.newClient().register(new Authenticator( "wineuser", "winepass"));
WebTarget targetSecret = clientSecret.target("http://localhost:8080").path("/RestRestEasyJquerySqlite2Hibernate/rest/wines");

wine.setId( 1231);
wine.setName( "secret wine name_" + dateKey);
wine.setCountry( "secret wine country_" + dateKey);
wine.setGrapes( "secret wine grapes_" + dateKey);
wine.setRegion( "secret wine region_" + dateKey);
try { 
    wine = targetSecret.path( "secret").request( MediaType.APPLICATION_JSON_TYPE).post( Entity.entity( wine, MediaType.APPLICATION_JSON_TYPE), Wine.class);
    System.out.println( "SECRET created wine: " + wine);
} catch( Exception e) {
    System.out.println( "ERROR: Back on the client: exception");
    e.printStackTrace();
}
1
Can u check if you hit the same url in browser you get a login dialog. - gladiator
@Ravikant Sharma - good question! Thank you and congrats with the +50. I made a JQuery performing the Post query ... so I got the basic user login. I did not succeed to login. Aha ... so I started a tomcat server from within Eclipse ... but that one had no user data configured. I configured a seperate Tomcat. SO, please post your comment as an answer and you will get the +50! - tm1701
Pro tips for posting: (a) we don't use [solved] title amendments here, using the acceptance 'tick' is sufficient; (b) we prefer answers to be given below, and not as edits to the question; (c) titles are best as plain, flowing English, without :: and | separator devices to introduce home-made tags - use the tagging system for that. - halfer

1 Answers

1
votes

The quoted software was correct. The deployment was wrong.

The problem of getting the 401 exception was that the software was deployed on the Eclipse linked private Tomcat server. On that server no configuration was made with users.

The solution of the problem was to export the WAR file to the separate Tomcat server. On this Tomcat server I configured the users via the tomcat-users config file.