1

I'm currently using http://www.dropwizard.io/1.1.0/docs/manual/auth.html# Dropwizard-Authentication in my Application. But i like to do the authentication "manualy" which means from a specific login/logout API call on a not authenticated REST interface.

Is there any possibility to forward an REST Call to the Authentication?

@POST
@Path("login")
@Consumes(MediaType.APPLICATION_JSON)
@Timed
@UnitOfWork
public Optional<LoginResponse> login(LoginRequest request) {
    // TODO forward login request to authentication
    return null;
}

Thx in advance

IEE1394
  • 1,181
  • 13
  • 33
  • I would suggest to reconsider your approach. Maybe you are thinking in webserver pages flow. But this is REST API and I haven't seen something like this anywhere (the "to forward a REST call"). You don't expect the client not to know what should be done and usually you don't have HTTP cookies and so on to maintain the "user session" after login and between requests. – zloster Mar 29 '17 at 09:29
  • Your approach should be to have API endpoint which will return some token that your server generates on successful login and is valid for some duration. See for example JWT: https://jwt.io/ Then you protect all the other API endpoints to check the HTTP request headers for a valid token. – zloster Mar 29 '17 at 09:29
  • There is a third party dropwizard module that is implementing the mentioned functionality. Take a look at: https://github.com/dhatim/dropwizard-jwt-cookie-authentication – zloster Mar 29 '17 at 10:19
  • Sorry, the mentioned project uses cookies to deliver the JWT tokens. It will help if a browser web application is the consumer. There is also this: https://github.com/ToastShaman/dropwizard-auth-jwt - which implements the JWT tokens as I explained: you have API endpoint you get token after successful authorisation and then use the token to call othere API endpoints. – zloster Mar 29 '17 at 14:36
  • By the sounds of it, your forwarding is to a different endpoint over rest. So, simply create a jersey client and make that call. – pandaadb Mar 31 '17 at 12:27

1 Answers1

1

Thx for helping me. I found a solution like that:

Adding an Authenticator to the REST Client

    client = ClientBuilder.newClient();
    authenticator = new Authenticator();
    client.register(authenticator);

Setup the Authenticator on Login-Successfull

    final UserAPIResponse response = create(request, UserAPI.PATH_ATTRIBUTE_DEFINITION_LOGIN);
    if (response == null || response.isFailed()) {
        connector.setupAuthenticator(null, null);
    } else {
        connector.setupAuthenticator(request.getUsername(), request.getPassword());
    }

And here is the Authenticator

class Authenticator implements ClientRequestFilter {

@Override
public void filter(ClientRequestContext requestContext) throws IOException {
    final MultivaluedMap<String, Object> headers = requestContext.getHeaders();
    final String basicAuthentication = getBasicAuthentication();
    if (basicAuthentication == null) return;
    headers.add("Authorization", basicAuthentication);

}

void setup(String username, String password) {
    this.user = username;
    this.password = password;
}

private String getBasicAuthentication() {
    if (user == null || password == null) return null;
    final String token = this.user + ":" + this.password;
    try {
        return "BASIC " + DatatypeConverter.printBase64Binary(token.getBytes("UTF-8"));
    } catch (final UnsupportedEncodingException ex) {
        throw new IllegalStateException("Cannot encode with UTF-8", ex);
    }
}

private String password;

private String user;

}

on the server side i have an Authenticator

public class UserAuthenticator implements Authenticator<BasicCredentials, User> {

UserAuthenticator(UserDAO userDAO) {
    this.userDAO = userDAO;
}

@UnitOfWork
@Override
public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException {
    final String username = credentials.getUsername();
    final Optional<DbUser> result = userDAO.getByName(username);
    if (!result.isPresent()) return Optional.empty();

    final DbUser user = result.get();
    final String password = credentials.getPassword();
    if (!StringUtils.equals(password, user.getPassword())) return Optional.empty();

    if (!user.isOnline()) return Optional.empty();
    user.handleAction();
    userDAO.save(user);

    return Optional.of(UserMgr.convert(user));
}

private final UserDAO userDAO;

}

And to get em working correctly:

SessionDao dao = new SessionDao(hibernateBundle.getSessionFactory());
ExampleAuthenticator exampleAuthenticator = new      UnitOfWorkAwareProxyFactory(hibernateBundle)
           .create(ExampleAuthenticator.class, SessionDao.class, dao);

So finally there is one REST-Call to login the User and the authentication is done on the result by the client automatically.

IEE1394
  • 1,181
  • 13
  • 33