com.linecorp.armeria.server.http.auth.AuthServiceTest.java Source code

Java tutorial

Introduction

Here is the source code for com.linecorp.armeria.server.http.auth.AuthServiceTest.java

Source

/*
 * Copyright 2016 LINE Corporation
 *
 * LINE Corporation licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package com.linecorp.armeria.server.http.auth;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Base64.Encoder;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.CompletableFuture;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.assertj.core.util.Strings;
import org.junit.Test;

import com.google.common.collect.ImmutableMap;

import com.linecorp.armeria.common.http.HttpHeaderNames;
import com.linecorp.armeria.common.http.HttpRequest;
import com.linecorp.armeria.common.http.HttpResponseWriter;
import com.linecorp.armeria.common.http.HttpStatus;
import com.linecorp.armeria.server.ServerBuilder;
import com.linecorp.armeria.server.ServiceRequestContext;
import com.linecorp.armeria.server.http.AbstractHttpService;
import com.linecorp.armeria.server.http.HttpService;
import com.linecorp.armeria.server.logging.LoggingService;
import com.linecorp.armeria.test.AbstractServerTest;

public class AuthServiceTest extends AbstractServerTest {

    private static final Encoder BASE64_ENCODER = Base64.getEncoder();

    @Override
    protected void configureServer(ServerBuilder sb) throws Exception {
        // Auth with arbitrary authorizer
        Authorizer<HttpRequest> authorizer = (ctx, req) -> CompletableFuture
                .supplyAsync(() -> "unit test".equals(req.headers().get(HttpHeaderNames.AUTHORIZATION)));
        sb.serviceAt("/", new AbstractHttpService() {
            @Override
            protected void doGet(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) {
                res.respond(HttpStatus.OK);
            }
        }.decorate(HttpAuthService.newDecorator(authorizer)).decorate(LoggingService::new));

        // Auth with HTTP basic
        final Map<String, String> usernameToPassword = ImmutableMap.of("brown", "cony", "pangyo", "choco");
        Authorizer<BasicToken> httpBasicAuthorizer = (ctx, token) -> {
            String username = token.username();
            String password = token.password();
            return CompletableFuture.completedFuture(password.equals(usernameToPassword.get(username)));
        };
        sb.serviceAt("/basic", new AbstractHttpService() {
            @Override
            protected void doGet(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) {
                res.respond(HttpStatus.OK);
            }
        }.decorate(new HttpAuthServiceBuilder().addBasicAuth(httpBasicAuthorizer).newDecorator())
                .decorate(LoggingService::new));

        // Auth with OAuth1a
        Authorizer<OAuth1aToken> oAuth1aAuthorizer = (ctx, token) -> CompletableFuture
                .completedFuture("dummy_signature".equals(token.signature()));
        sb.serviceAt("/oauth1a", new AbstractHttpService() {
            @Override
            protected void doGet(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) {
                res.respond(HttpStatus.OK);
            }
        }.decorate(new HttpAuthServiceBuilder().addOAuth1a(oAuth1aAuthorizer).newDecorator())
                .decorate(LoggingService::new));

        // Auth with OAuth2
        Authorizer<OAuth2Token> oAuth2aAuthorizer = (ctx, token) -> CompletableFuture
                .completedFuture("dummy_oauth2_token".equals(token.accessToken()));
        sb.serviceAt("/oauth2", new AbstractHttpService() {
            @Override
            protected void doGet(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) {
                res.respond(HttpStatus.OK);
            }
        }.decorate(new HttpAuthServiceBuilder().addOAuth2(oAuth2aAuthorizer).newDecorator())
                .decorate(LoggingService::new));

        // Auth with all predicates above!
        HttpService compositeService = new AbstractHttpService() {
            @Override
            protected void doGet(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) {
                res.respond(HttpStatus.OK);
            }
        };
        HttpAuthService compositeAuth = new HttpAuthServiceBuilder().add(authorizer)
                .addBasicAuth(httpBasicAuthorizer).addOAuth1a(oAuth1aAuthorizer).addOAuth2(oAuth2aAuthorizer)
                .build(compositeService);
        sb.serviceAt("/composite", compositeAuth.decorate(LoggingService::new));
    }

    @Test
    public void testAuth() throws Exception {
        try (CloseableHttpClient hc = HttpClients.createMinimal()) {
            try (CloseableHttpResponse res = hc.execute(getRequest("/", "unit test"))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 200 OK"));
            }
            try (CloseableHttpResponse res = hc.execute(getRequest("/", "UNIT TEST"))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 401 Unauthorized"));
            }
        }
    }

    @Test
    public void testBasicAuth() throws Exception {
        try (CloseableHttpClient hc = HttpClients.createMinimal()) {
            try (CloseableHttpResponse res = hc
                    .execute(basicGetRequest("/basic", BasicToken.of("brown", "cony")))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 200 OK"));
            }
            try (CloseableHttpResponse res = hc
                    .execute(basicGetRequest("/basic", BasicToken.of("pangyo", "choco")))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 200 OK"));
            }
            try (CloseableHttpResponse res = hc.execute(new HttpGet(uri("/basic")))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 401 Unauthorized"));
            }
            try (CloseableHttpResponse res = hc
                    .execute(basicGetRequest("/basic", BasicToken.of("choco", "pangyo")))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 401 Unauthorized"));
            }
        }
    }

    @Test
    public void testOAuth1a() throws Exception {
        try (CloseableHttpClient hc = HttpClients.createMinimal()) {
            Map<String, String> passToken = ImmutableMap.<String, String>builder().put("realm", "dummy_realm")
                    .put("oauth_consumer_key", "dummy_consumer_key").put("oauth_token", "dummy_oauth1a_token")
                    .put("oauth_signature_method", "dummy").put("oauth_signature", "dummy_signature")
                    .put("oauth_timestamp", "0").put("oauth_nonce", "dummy_nonce").put("version", "1.0").build();
            try (CloseableHttpResponse res = hc
                    .execute(oauth1aGetRequest("/oauth1a", OAuth1aToken.of(passToken)))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 200 OK"));
            }
            Map<String, String> failToken = ImmutableMap.<String, String>builder().put("realm", "dummy_realm")
                    .put("oauth_consumer_key", "dummy_consumer_key").put("oauth_token", "dummy_oauth1a_token")
                    .put("oauth_signature_method", "dummy").put("oauth_signature", "DUMMY_signature")
                    .put("oauth_timestamp", "0").put("oauth_nonce", "dummy_nonce").put("version", "1.0").build();
            try (CloseableHttpResponse res = hc
                    .execute(oauth1aGetRequest("/oauth1a", OAuth1aToken.of(failToken)))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 401 Unauthorized"));
            }
        }
    }

    @Test
    public void testOAuth2() throws Exception {
        try (CloseableHttpClient hc = HttpClients.createMinimal()) {
            try (CloseableHttpResponse res = hc
                    .execute(oauth2GetRequest("/oauth2", OAuth2Token.of("dummy_oauth2_token")))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 200 OK"));
            }
            try (CloseableHttpResponse res = hc
                    .execute(oauth2GetRequest("/oauth2", OAuth2Token.of("DUMMY_oauth2_token")))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 401 Unauthorized"));
            }
        }
    }

    @Test
    public void testCompositeAuth() throws Exception {
        try (CloseableHttpClient hc = HttpClients.createMinimal()) {
            try (CloseableHttpResponse res = hc.execute(getRequest("/composite", "unit test"))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 200 OK"));
            }
            try (CloseableHttpResponse res = hc
                    .execute(basicGetRequest("/composite", BasicToken.of("brown", "cony")))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 200 OK"));
            }
            Map<String, String> passToken = ImmutableMap.<String, String>builder().put("realm", "dummy_realm")
                    .put("oauth_consumer_key", "dummy_consumer_key").put("oauth_token", "dummy_oauth1a_token")
                    .put("oauth_signature_method", "dummy").put("oauth_signature", "dummy_signature")
                    .put("oauth_timestamp", "0").put("oauth_nonce", "dummy_nonce").put("version", "1.0").build();
            try (CloseableHttpResponse res = hc
                    .execute(oauth1aGetRequest("/composite", OAuth1aToken.of(passToken)))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 200 OK"));
            }
            try (CloseableHttpResponse res = hc
                    .execute(oauth2GetRequest("/composite", OAuth2Token.of("dummy_oauth2_token")))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 200 OK"));
            }
            try (CloseableHttpResponse res = hc.execute(new HttpGet(uri("/composite")))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 401 Unauthorized"));
            }
            try (CloseableHttpResponse res = hc
                    .execute(basicGetRequest("/composite", BasicToken.of("choco", "pangyo")))) {
                assertThat(res.getStatusLine().toString(), is("HTTP/1.1 401 Unauthorized"));
            }
        }
    }

    private static HttpRequestBase getRequest(String path, String authorization) {
        HttpGet request = new HttpGet(uri(path));
        request.addHeader("Authorization", authorization);
        return request;
    }

    private static HttpRequestBase basicGetRequest(String path, BasicToken basicToken) {
        HttpGet request = new HttpGet(uri(path));
        request.addHeader("Authorization", "Basic " + BASE64_ENCODER.encodeToString(
                (basicToken.username() + ':' + basicToken.password()).getBytes(StandardCharsets.US_ASCII)));
        return request;
    }

    private static HttpRequestBase oauth1aGetRequest(String path, OAuth1aToken oAuth1aToken) {
        HttpGet request = new HttpGet(uri(path));
        StringBuilder authorization = new StringBuilder("OAuth ");
        String realm = oAuth1aToken.realm();
        if (!Strings.isNullOrEmpty(realm)) {
            authorization.append("realm=\"");
            authorization.append(realm);
            authorization.append("\",");
        }
        authorization.append("oauth_consumer_key=\"");
        authorization.append(oAuth1aToken.consumerKey());
        authorization.append("\",oauth_token=\"");
        authorization.append(oAuth1aToken.token());
        authorization.append("\",oauth_signature_method=\"");
        authorization.append(oAuth1aToken.signatureMethod());
        authorization.append("\",oauth_signature=\"");
        authorization.append(oAuth1aToken.signature());
        authorization.append("\",oauth_timestamp=\"");
        authorization.append(oAuth1aToken.timestamp());
        authorization.append("\",oauth_nonce=\"");
        authorization.append(oAuth1aToken.nonce());
        authorization.append("\",version=\"");
        authorization.append(oAuth1aToken.version());
        authorization.append("\"");
        for (Entry<String, String> entry : oAuth1aToken.additionals().entrySet()) {
            authorization.append("\",");
            authorization.append(entry.getKey());
            authorization.append("=\"");
            authorization.append(entry.getValue());
            authorization.append("\"");
        }
        request.addHeader("Authorization", authorization.toString());
        return request;
    }

    private static HttpRequestBase oauth2GetRequest(String path, OAuth2Token oAuth2Token) {
        HttpGet request = new HttpGet(uri(path));
        request.addHeader("Authorization", "Bearer " + oAuth2Token.accessToken());
        return request;
    }
}