2

I have a spring rest api that is secured using base64 authentication through a database. Is it possible to then take another rest api and somehow authenticate through the first api?

2
  • btw, the backend uses the UserDetailsService Commented Feb 2, 2015 at 21:57
  • why not use OAuth? It's a more secure way than HTTP basic authentication. Here's a blog post that might help. stormpath.com/blog/secure-your-rest-api-right-way Commented Feb 4, 2015 at 20:34

3 Answers 3

5

Have you considered securing your APIs with OAuth-based authentication and API key management. HTTP Basic Authentication isn't really consider ideal from a security perspective and username and password have another set of security issues for APIs

Either way, you might consider using Stormpath to make this REALLY easy for you. Take a look at this guide, it supports both HTTP basic and OAuth.

This sample code will give you a good idea of how easy this is.

Let's suppose you want to expose an operation called startEngines() and you want to secure it. You will also need to expose a new operation to get access tokens, in this example String getAccessToken(ApiKey).

Your users will run something like this:

@Test
public void executeSomeOauth2AuthenticatedOperation() {

    String userApiKeyPath = System.getProperty("user.home") + "/.stormpath/apiKey_4Yrc0TJ5sBFldwtu6nfzf5.properties";
    ApiKey userApiKey = ApiKeys.builder().setFileLocation(userApiKeyPath).build();

    //Developer requests access token
    String accessToken = getAccessToken(userApiKey);

    //Developer executes an authenticated operation (e.g startEngines()) with the provided accessToken
    if (startEngines(accessToken)) {
        System.out.print("Client-side message: Execution allowed");
    } else {
        System.out.print("Client-side message: Execution denied");
    }
}

Your code will look like this:

String path = System.getProperty("user.home") + "/.stormpath/apiKey.properties";
String applicationUrl = "https://api.stormpath.com/v1/applications/2TqboZ1qo73eDM4gTo2H94";
Client client = Clients.builder().setApiKey(ApiKeys.builder().setFileLocation(path).build()).build();
Application application = client.getResource(applicationUrl, Application.class);

public String getAccessToken(ApiKey apiKey) {
    HttpRequest request = createOauthAuthenticationRequest(apiKey);
    AccessTokenResult accessTokenResult = (AccessTokenResult) application.authenticateApiRequest(request);
    System.out.println(accessTokenResult.getScope());
    return accessTokenResult.getTokenResponse().getAccessToken();
}

public boolean startEngines(String accessToken) {
    HttpRequest request = createRequestForOauth2AuthenticatedOperation(accessToken);
    try {
        OauthAuthenticationResult result = application.authenticateOauthRequest(request).execute();
        System.out.println(result.getAccount().getEmail() + " is about to start the engines!");

        doStartEngines(); //Here you will actually call your internal doStartEngines() operation
        return true;

    } catch (AccessTokenOauthException e) {

        //This accessToken is not allowed to start the engines
        System.out.print("AccessToken: " + accessToken + " just tried to start the engines. He is not allowed to do so.");
        return false;

    }
}

private HttpRequest createOauthAuthenticationRequest(ApiKey apiKey) {
    try {
        String credentials = apiKey.getId() + ":" + apiKey.getSecret();

        Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
        headers.put("Accept", new String[]{"application/json"});
        headers.put("Content-Type", new String[]{"application/x-www-form-urlencoded"});
        headers.put("Authorization", new String[]{"Basic " + Base64.encodeBase64String(credentials.getBytes("UTF-8"))});

        Map<String, String[]> parameters = new LinkedHashMap<String, String[]>();
        parameters.put("grant_type", new String[]{"client_credentials"});

        HttpRequest request = HttpRequests.method(HttpMethod.POST)
                .headers(headers)
                .parameters(parameters)
                .build();
        return request;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

private HttpRequest createRequestForOauth2AuthenticatedOperation(String token) {
    try {
        Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
        headers.put("Accept", new String[]{"application/json"});
        headers.put("Authorization", new String[]{"Bearer " + token});
        HttpRequest request = HttpRequests.method(HttpMethod.GET)
                .headers(headers)
                .build();
        return request;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

private void doStartEngines() {
    System.out.println("Server-side message: Engines started!!!");
}

For the sake of simplicity I made all this code run in the same machine (no network communication between the client- and server-side code). You will actually need to expose startEngines() and String getAccessToken(ApiKey) via Rest API using Spring and have your end-users access them via the network.

Give it a try, it should a pretty easy and quick solution. :)

Full disclosure- I work at Stormpath

Sign up to request clarification or add additional context in comments.

Comments

0

Base64 is an encoding mechanism, not an authentication scheme. I assume you mean you are using basic authentication, which is the username and password base64 encoded in the Authorization HTTP header.

If the other service also uses basic authentication and check username and password against the same credential database, then you will be able to use the same base64 encoded string to authenticate against the other REST service.

Comments

0

All I had to do was have the class in my second API that catches all the requests call the first API, which already has the connection to my database, sending in the basic authentication header to validate the credentials.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.