diff --git a/core/trino-main/src/main/java/io/trino/server/security/AbstractBearerAuthenticator.java b/core/trino-main/src/main/java/io/trino/server/security/AbstractBearerAuthenticator.java index dfcc30519450..611099332534 100644 --- a/core/trino-main/src/main/java/io/trino/server/security/AbstractBearerAuthenticator.java +++ b/core/trino-main/src/main/java/io/trino/server/security/AbstractBearerAuthenticator.java @@ -18,24 +18,15 @@ import javax.ws.rs.container.ContainerRequestContext; -import java.security.Principal; import java.util.List; import java.util.Optional; import static com.google.common.net.HttpHeaders.AUTHORIZATION; import static java.lang.String.format; -import static java.util.Objects.requireNonNull; public abstract class AbstractBearerAuthenticator implements Authenticator { - private final UserMapping userMapping; - - protected AbstractBearerAuthenticator(UserMapping userMapping) - { - this.userMapping = requireNonNull(userMapping, "userMapping is null"); - } - @Override public Identity authenticate(ContainerRequestContext request) throws AuthenticationException @@ -47,15 +38,7 @@ public Identity authenticate(ContainerRequestContext request, String token) throws AuthenticationException { try { - Optional principal = extractPrincipalFromToken(token); - if (principal.isEmpty()) { - throw needAuthentication(request, "Invalid credentials"); - } - - String authenticatedUser = userMapping.mapUser(principal.get().getName()); - return Identity.forUser(authenticatedUser) - .withPrincipal(principal.get()) - .build(); + return createIdentity(token).orElseThrow(() -> needAuthentication(request, "Invalid credentials")); } catch (JwtException | UserMappingException e) { throw needAuthentication(request, e.getMessage()); @@ -88,7 +71,8 @@ public String extractToken(ContainerRequestContext request) return token; } - protected abstract Optional extractPrincipalFromToken(String token); + protected abstract Optional createIdentity(String token) + throws UserMappingException; protected abstract AuthenticationException needAuthentication(ContainerRequestContext request, String message); } diff --git a/core/trino-main/src/main/java/io/trino/server/security/jwt/JwtAuthenticator.java b/core/trino-main/src/main/java/io/trino/server/security/jwt/JwtAuthenticator.java index 1fb38a9b348b..5989470f0384 100644 --- a/core/trino-main/src/main/java/io/trino/server/security/jwt/JwtAuthenticator.java +++ b/core/trino-main/src/main/java/io/trino/server/security/jwt/JwtAuthenticator.java @@ -19,12 +19,14 @@ import io.jsonwebtoken.SigningKeyResolver; import io.trino.server.security.AbstractBearerAuthenticator; import io.trino.server.security.AuthenticationException; +import io.trino.server.security.UserMapping; +import io.trino.server.security.UserMappingException; import io.trino.spi.security.BasicPrincipal; +import io.trino.spi.security.Identity; import javax.inject.Inject; import javax.ws.rs.container.ContainerRequestContext; -import java.security.Principal; import java.util.Optional; import static io.trino.server.security.UserMapping.createUserMapping; @@ -34,11 +36,11 @@ public class JwtAuthenticator { private final JwtParser jwtParser; private final String principalField; + private final UserMapping userMapping; @Inject public JwtAuthenticator(JwtAuthenticatorConfig config, SigningKeyResolver signingKeyResolver) { - super(createUserMapping(config.getUserMappingPattern(), config.getUserMappingFile())); principalField = config.getPrincipalField(); JwtParserBuilder jwtParser = Jwts.parserBuilder() @@ -51,15 +53,22 @@ public JwtAuthenticator(JwtAuthenticatorConfig config, SigningKeyResolver signin jwtParser.requireAudience(config.getRequiredAudience()); } this.jwtParser = jwtParser.build(); + userMapping = createUserMapping(config.getUserMappingPattern(), config.getUserMappingFile()); } @Override - protected Optional extractPrincipalFromToken(String token) + protected Optional createIdentity(String token) + throws UserMappingException { - return Optional.ofNullable(jwtParser.parseClaimsJws(token) + Optional principal = Optional.ofNullable(jwtParser.parseClaimsJws(token) .getBody() - .get(principalField, String.class)) - .map(BasicPrincipal::new); + .get(principalField, String.class)); + if (principal.isEmpty()) { + return Optional.empty(); + } + return Optional.of(Identity.forUser(userMapping.mapUser(principal.get())) + .withPrincipal(new BasicPrincipal(principal.get())) + .build()); } @Override diff --git a/core/trino-main/src/main/java/io/trino/server/security/oauth2/OAuth2Authenticator.java b/core/trino-main/src/main/java/io/trino/server/security/oauth2/OAuth2Authenticator.java index 0482b9393099..23f391e7542a 100644 --- a/core/trino-main/src/main/java/io/trino/server/security/oauth2/OAuth2Authenticator.java +++ b/core/trino-main/src/main/java/io/trino/server/security/oauth2/OAuth2Authenticator.java @@ -13,15 +13,20 @@ */ package io.trino.server.security.oauth2; +import com.google.common.collect.ImmutableSet; import io.trino.server.security.AbstractBearerAuthenticator; import io.trino.server.security.AuthenticationException; +import io.trino.server.security.UserMapping; +import io.trino.server.security.UserMappingException; import io.trino.spi.security.BasicPrincipal; +import io.trino.spi.security.Identity; import javax.inject.Inject; import javax.ws.rs.container.ContainerRequestContext; import java.net.URI; -import java.security.Principal; +import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -36,23 +41,33 @@ public class OAuth2Authenticator { private final OAuth2Service service; private final String principalField; + private final Optional groupsField; + private final UserMapping userMapping; @Inject public OAuth2Authenticator(OAuth2Service service, OAuth2Config config) { - super(createUserMapping(config.getUserMappingPattern(), config.getUserMappingFile())); this.service = requireNonNull(service, "service is null"); this.principalField = config.getPrincipalField(); + groupsField = requireNonNull(config.getGroupsField(), "groupsField is null"); + userMapping = createUserMapping(config.getUserMappingPattern(), config.getUserMappingFile()); } @Override - protected Optional extractPrincipalFromToken(String token) + protected Optional createIdentity(String token) + throws UserMappingException { try { - return service.convertTokenToClaims(token) - .map(claims -> claims.get(principalField)) - .map(String.class::cast) - .map(BasicPrincipal::new); + Optional> claims = service.convertTokenToClaims(token); + if (claims.isEmpty()) { + return Optional.empty(); + } + String principal = (String) claims.get().get(principalField); + Identity.Builder builder = Identity.forUser(userMapping.mapUser(principal)); + builder.withPrincipal(new BasicPrincipal(principal)); + groupsField.flatMap(field -> Optional.ofNullable((List) claims.get().get(field))) + .ifPresent(groups -> builder.withGroups(ImmutableSet.copyOf(groups))); + return Optional.of(builder.build()); } catch (ChallengeFailedException e) { return Optional.empty(); diff --git a/core/trino-main/src/main/java/io/trino/server/security/oauth2/OAuth2Config.java b/core/trino-main/src/main/java/io/trino/server/security/oauth2/OAuth2Config.java index 5f978467907f..fb8bc874f012 100644 --- a/core/trino-main/src/main/java/io/trino/server/security/oauth2/OAuth2Config.java +++ b/core/trino-main/src/main/java/io/trino/server/security/oauth2/OAuth2Config.java @@ -49,6 +49,7 @@ public class OAuth2Config private String clientSecret; private Set scopes = ImmutableSet.of(OPENID_SCOPE); private String principalField = "sub"; + private Optional groupsField = Optional.empty(); private List additionalAudiences = Collections.emptyList(); private Duration challengeTimeout = new Duration(15, TimeUnit.MINUTES); private Optional userMappingPattern = Optional.empty(); @@ -222,6 +223,19 @@ public OAuth2Config setPrincipalField(String principalField) return this; } + public Optional getGroupsField() + { + return groupsField; + } + + @Config("http-server.authentication.oauth2.groups-field") + @ConfigDescription("Groups field in the claim") + public OAuth2Config setGroupsField(String groupsField) + { + this.groupsField = Optional.ofNullable(groupsField); + return this; + } + @MinDuration("1ms") @NotNull public Duration getChallengeTimeout() diff --git a/core/trino-main/src/main/java/io/trino/server/ui/OAuth2WebUiAuthenticationFilter.java b/core/trino-main/src/main/java/io/trino/server/ui/OAuth2WebUiAuthenticationFilter.java index e259e4db9642..a4a9ddf6fab8 100644 --- a/core/trino-main/src/main/java/io/trino/server/ui/OAuth2WebUiAuthenticationFilter.java +++ b/core/trino-main/src/main/java/io/trino/server/ui/OAuth2WebUiAuthenticationFilter.java @@ -28,6 +28,7 @@ import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.core.Response; +import java.util.List; import java.util.Map; import java.util.Optional; @@ -50,6 +51,7 @@ public class OAuth2WebUiAuthenticationFilter private final String principalField; private final OAuth2Service service; private final UserMapping userMapping; + private final Optional groupsField; @Inject public OAuth2WebUiAuthenticationFilter(OAuth2Service service, OAuth2Config oauth2Config) @@ -58,6 +60,7 @@ public OAuth2WebUiAuthenticationFilter(OAuth2Service service, OAuth2Config oauth requireNonNull(oauth2Config, "oauth2Config is null"); this.userMapping = UserMapping.createUserMapping(oauth2Config.getUserMappingPattern(), oauth2Config.getUserMappingFile()); this.principalField = oauth2Config.getPrincipalField(); + groupsField = requireNonNull(oauth2Config.getGroupsField(), "groupsField is null"); } @Override @@ -101,9 +104,11 @@ public void filter(ContainerRequestContext request) return; } String principalName = (String) principal; - setAuthenticatedIdentity(request, Identity.forUser(userMapping.mapUser(principalName)) - .withPrincipal(new BasicPrincipal(principalName)) - .build()); + Identity.Builder builder = Identity.forUser(userMapping.mapUser(principalName)); + builder.withPrincipal(new BasicPrincipal(principalName)); + groupsField.flatMap(field -> Optional.ofNullable((List) claims.get().get(field))) + .ifPresent(groups -> builder.withGroups(ImmutableSet.copyOf(groups))); + setAuthenticatedIdentity(request, builder.build()); } catch (UserMappingException e) { sendErrorMessage(request, UNAUTHORIZED, firstNonNull(e.getMessage(), "Unauthorized")); diff --git a/core/trino-main/src/test/java/io/trino/server/security/TestResourceSecurity.java b/core/trino-main/src/test/java/io/trino/server/security/TestResourceSecurity.java index 55ce3f382052..8923f9f6887a 100644 --- a/core/trino-main/src/test/java/io/trino/server/security/TestResourceSecurity.java +++ b/core/trino-main/src/test/java/io/trino/server/security/TestResourceSecurity.java @@ -15,10 +15,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.io.Resources; import com.google.inject.Key; +import com.google.inject.Module; import io.airlift.http.server.HttpServerConfig; import io.airlift.http.server.HttpServerInfo; import io.airlift.http.server.testing.TestingHttpServer; @@ -27,7 +29,6 @@ import io.jsonwebtoken.JwsHeader; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; import io.trino.plugin.base.security.AllowAllSystemAccessControl; import io.trino.security.AccessControl; import io.trino.security.AccessControlManager; @@ -38,13 +39,17 @@ import io.trino.spi.security.BasicPrincipal; import io.trino.spi.security.Identity; import io.trino.spi.security.SystemSecurityContext; +import okhttp3.Cookie; +import okhttp3.CookieJar; import okhttp3.Credentials; import okhttp3.Headers; +import okhttp3.HttpUrl; import okhttp3.JavaNetCookieJar; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import javax.crypto.SecretKey; @@ -71,9 +76,13 @@ import java.util.Base64; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.collect.Iterables.getOnlyElement; @@ -86,8 +95,10 @@ import static io.trino.client.ProtocolHeaders.TRINO_HEADERS; import static io.trino.metadata.MetadataManager.createTestMetadataManager; import static io.trino.server.security.ResourceSecurity.AccessType.AUTHENTICATED_USER; +import static io.trino.server.security.ResourceSecurity.AccessType.WEB_UI; import static io.trino.server.security.oauth2.OAuth2Service.NONCE; -import static io.trino.server.security.oauth2.OAuth2Service.hashNonce; +import static io.trino.server.ui.FormWebUiAuthenticationFilter.UI_LOCATION; +import static io.trino.server.ui.OAuthWebUiCookie.OAUTH2_COOKIE; import static io.trino.spi.security.AccessDeniedException.denyImpersonateUser; import static io.trino.spi.security.AccessDeniedException.denyReadSystemInformationAccess; import static io.trino.testing.assertions.Assert.assertEquals; @@ -126,6 +137,8 @@ public class TestResourceSecurity private static final String MANAGEMENT_USER_LOGIN = MANAGEMENT_USER + "@allowed"; private static final String MANAGEMENT_PASSWORD = "management-password"; private static final String HMAC_KEY = Resources.getResource("hmac_key.txt").getPath(); + private static final String JWK_KEY_ID = "test-rsa"; + private static final String GROUPS_CLAIM = "groups"; private static final PrivateKey JWK_PRIVATE_KEY; private static final ObjectMapper json = new ObjectMapper(); @@ -293,39 +306,18 @@ public void testPasswordAuthenticatorUserMapping() // Normally this would result in an impersonation check to the X-Trino-User, but the password // authenticator has a hack to clear X-Trino-User in this case. Request request = new Request.Builder() - .url(getLocation(httpServerInfo.getHttpsUri(), "/username")) + .url(getLocation(httpServerInfo.getHttpsUri(), "/protocol/identity")) .addHeader("Authorization", Credentials.basic(TEST_USER_LOGIN, TEST_PASSWORD)) .addHeader("X-Trino-User", TEST_USER_LOGIN) .build(); try (Response response = client.newCall(request).execute()) { assertEquals(response.code(), SC_OK); assertEquals(response.header("user"), TEST_USER); + assertEquals(response.header("principal"), TEST_USER_LOGIN); } } } - @javax.ws.rs.Path("/username") - public static class TestResource - { - private final HttpRequestSessionContextFactory sessionContextFactory; - - @Inject - public TestResource(AccessControl accessControl) - { - this.sessionContextFactory = new HttpRequestSessionContextFactory(createTestMetadataManager(), ImmutableSet::of, accessControl); - } - - @ResourceSecurity(AUTHENTICATED_USER) - @GET - public javax.ws.rs.core.Response echoToken(@Context HttpServletRequest servletRequest, @Context HttpHeaders httpHeaders) - { - Identity identity = sessionContextFactory.extractAuthorizedIdentity(servletRequest, httpHeaders, Optional.empty()); - return javax.ws.rs.core.Response.ok() - .header("user", identity.getUser()) - .build(); - } - } - @Test public void testPasswordAuthenticatorWithInsecureHttp() throws Exception @@ -516,7 +508,7 @@ public void testJwtWithJwkAuthenticator() String token = Jwts.builder() .signWith(JWK_PRIVATE_KEY) - .setHeaderParam(JwsHeader.KEY_ID, "test-rsa") + .setHeaderParam(JwsHeader.KEY_ID, JWK_KEY_ID) .setSubject("test-user") .setExpiration(Date.from(ZonedDateTime.now().plusMinutes(5).toInstant())) .compact(); @@ -551,67 +543,16 @@ private void verifyOAuth2Authenticator(boolean webUiEnabled, Optional pr .cookieJar(new JavaNetCookieJar(cookieManager)) .build(); - String clientId = "client"; - Date tokenExpiration = Date.from(ZonedDateTime.now().plusMinutes(5).toInstant()); - String issuer = "http://example.com/"; - JwtBuilder accessTokenBuilder = Jwts.builder() - .signWith(JWK_PRIVATE_KEY) - .setHeaderParam(JwsHeader.KEY_ID, "test-rsa") - .setIssuer(issuer) - .setAudience(clientId) - .setExpiration(tokenExpiration); - JwtBuilder idTokenBuilder = Jwts.builder() - .signWith(SignatureAlgorithm.RS256, JWK_PRIVATE_KEY) - .setHeaderParam(JwsHeader.KEY_ID, "test-rsa") - .setIssuer(issuer) - .setAudience(clientId) - .setExpiration(tokenExpiration); - if (principalField.isPresent()) { - accessTokenBuilder.claim(principalField.get(), "test-user"); - idTokenBuilder.claim(principalField.get(), "test-user"); - } - else { - accessTokenBuilder.setSubject("test-user"); - idTokenBuilder.setSubject("test-user"); - } - String accessToken = accessTokenBuilder.compact(); - - TestingHttpServer jwkServer = createTestingJwkServer(); - jwkServer.start(); - try (TestingTrinoServer server = TestingTrinoServer.builder() - .setProperties(ImmutableMap.builder() - .putAll(SECURE_PROPERTIES) - .put("http-server.authentication.type", "oauth2") - .put("web-ui.enabled", String.valueOf(webUiEnabled)) - .put("http-server.authentication.oauth2.issuer", issuer) - .put("http-server.authentication.oauth2.jwks-url", jwkServer.getBaseUrl().toString()) - .put("http-server.authentication.oauth2.state-key", "test-state-key") - .put("http-server.authentication.oauth2.auth-url", issuer) - .put("http-server.authentication.oauth2.token-url", issuer) - .put("http-server.authentication.oauth2.client-id", clientId) - .put("http-server.authentication.oauth2.client-secret", "client-secret") - .put("http-server.authentication.oauth2.principal-field", principalField.orElse("sub")) - .buildOrThrow()) - .setAdditionalModule(binder -> newOptionalBinder(binder, OAuth2Client.class) - .setBinding() - .toInstance(new OAuth2Client() - { - @Override - public URI getAuthorizationUri(String state, URI callbackUri, Optional nonceHash) - { - return URI.create("http://example.com/authorize?" + state); - } - - @Override - public OAuth2Response getOAuth2Response(String code, URI callbackUri) - { - if (!"TEST_CODE".equals(code)) { - throw new IllegalArgumentException("Expected TEST_CODE"); - } - return new OAuth2Response(accessToken, Optional.of(now().plus(5, ChronoUnit.MINUTES)), Optional.of(idTokenBuilder.compact())); - } - })) - .build()) { + try (TokenServer tokenServer = new TokenServer(principalField); + TestingTrinoServer server = TestingTrinoServer.builder() + .setProperties(ImmutableMap.builder() + .putAll(SECURE_PROPERTIES) + .put("web-ui.enabled", String.valueOf(webUiEnabled)) + .putAll(getOAuth2Properties(tokenServer)) + .put("http-server.authentication.oauth2.principal-field", principalField.orElse("sub")) + .buildOrThrow()) + .setAdditionalModule(oauth2Module(tokenServer)) + .build()) { server.getInstance(Key.get(AccessControlManager.class)).addSystemAccessControl(TestSystemAccessControl.NO_IMPERSONATION); HttpServerInfo httpServerInfo = server.getInstance(Key.get(HttpServerInfo.class)); @@ -620,14 +561,10 @@ public OAuth2Response getOAuth2Response(String code, URI callbackUri) // not logged in URI baseUri = httpServerInfo.getHttpsUri(); assertOk(client, getPublicLocation(baseUri)); - OAuthBearer bearer = assertAuthenticateOAuth2Bearer(client, getAuthorizedUserLocation(baseUri), "http://example.com/authorize"); assertAuthenticateOAuth2Bearer(client, getManagementLocation(baseUri), "http://example.com/authorize"); + OAuthBearer bearer = assertAuthenticateOAuth2Bearer(client, getAuthorizedUserLocation(baseUri), "http://example.com/authorize"); assertResponseCode(client, getInternalLocation(baseUri), SC_FORBIDDEN); - // We must add the nonce to the ID token we will soon generate. - idTokenBuilder.claim(NONCE, hashNonce(bearer.getNonceCookie().getValue())); - // The second call to `assertAuthenticateOAuth2Bearer` above overwrites the nonce cookie we need. - cookieManager.getCookieStore().add(cookieManager.getCookieStore().getURIs().get(0), bearer.getNonceCookie()); // login with the callback endpoint assertOk( client, @@ -636,12 +573,12 @@ public OAuth2Response getOAuth2Response(String code, URI callbackUri) .addParameter("code", "TEST_CODE") .addParameter("state", bearer.getState()) .toString()); - assertEquals(getOauthToken(client, bearer.getTokenServer()), accessToken); + assertEquals(getOauthToken(client, bearer.getTokenServer()), tokenServer.getAccessToken()); // if Web UI is using oauth so we should get a cookie if (webUiEnabled) { HttpCookie cookie = getOnlyElement(cookieManager.getCookieStore().getCookies()); - assertEquals(cookie.getValue(), accessToken); + assertEquals(cookie.getValue(), tokenServer.getAccessToken()); assertEquals(cookie.getPath(), "/ui/"); assertEquals(cookie.getDomain(), baseUri.getHost()); assertTrue(cookie.getMaxAge() > 0 && cookie.getMaxAge() < MINUTES.toSeconds(5)); @@ -655,14 +592,11 @@ public OAuth2Response getOAuth2Response(String code, URI callbackUri) OkHttpClient clientWithOAuthToken = client.newBuilder() .authenticator((route, response) -> response.request().newBuilder() - .header(AUTHORIZATION, "Bearer " + accessToken) + .header(AUTHORIZATION, "Bearer " + tokenServer.getAccessToken()) .build()) .build(); assertAuthenticationAutomatic(httpServerInfo.getHttpsUri(), clientWithOAuthToken); } - finally { - jwkServer.stop(); - } } private static OAuthBearer assertAuthenticateOAuth2Bearer(OkHttpClient client, String url, String expectedRedirect) @@ -730,6 +664,110 @@ public HttpCookie getNonceCookie() } } + @Test(dataProvider = "groups") + public void testOAuth2Groups(Optional> groups) + throws Exception + { + try (TokenServer tokenServer = new TokenServer(Optional.empty()); + TestingTrinoServer server = TestingTrinoServer.builder() + .setProperties(ImmutableMap.builder() + .putAll(SECURE_PROPERTIES) + .put("web-ui.enabled", "true") + .putAll(getOAuth2Properties(tokenServer)) + .put("http-server.authentication.oauth2.groups-field", GROUPS_CLAIM) + .build()) + .setAdditionalModule(oauth2Module(tokenServer)) + .build()) { + server.getInstance(Key.get(AccessControlManager.class)).addSystemAccessControl(TestSystemAccessControl.NO_IMPERSONATION); + HttpServerInfo httpServerInfo = server.getInstance(Key.get(HttpServerInfo.class)); + + String accessToken = tokenServer.issueAccessToken(groups); + OkHttpClient clientWithOAuthToken = client.newBuilder() + .authenticator((route, response) -> response.request().newBuilder() + .header(AUTHORIZATION, "Bearer " + accessToken) + .build()) + .build(); + + assertAuthenticationAutomatic(httpServerInfo.getHttpsUri(), clientWithOAuthToken); + + try (Response response = clientWithOAuthToken.newCall(new Request.Builder() + .url(getLocation(httpServerInfo.getHttpsUri(), "/protocol/identity")) + .build()) + .execute()) { + assertEquals(response.code(), SC_OK); + assertEquals(response.header("user"), TEST_USER); + assertEquals(response.header("principal"), TEST_USER); + assertEquals(response.header("groups"), groups.map(TestResource::toHeader).orElse("")); + } + + OkHttpClient clientWithOAuthCookie = client.newBuilder() + .cookieJar(new CookieJar() + { + @Override + public void saveFromResponse(HttpUrl url, List cookies) + { + } + + @Override + public List loadForRequest(HttpUrl url) + { + return ImmutableList.of(new Cookie.Builder() + .domain(httpServerInfo.getHttpsUri().getHost()) + .path(UI_LOCATION) + .name(OAUTH2_COOKIE) + .value(accessToken) + .httpOnly() + .secure() + .build()); + } + }) + .build(); + try (Response response = clientWithOAuthCookie.newCall(new Request.Builder() + .url(getLocation(httpServerInfo.getHttpsUri(), "/ui/api/identity")) + .build()) + .execute()) { + assertEquals(response.code(), SC_OK); + assertEquals(response.header("user"), TEST_USER); + assertEquals(response.header("principal"), TEST_USER); + assertEquals(response.header("groups"), groups.map(TestResource::toHeader).orElse("")); + } + } + } + + @DataProvider(name = "groups") + public static Object[][] groups() + { + return new Object[][] { + {Optional.empty()}, + {Optional.of(ImmutableSet.of())}, + {Optional.of(ImmutableSet.of("admin", "public"))} + }; + } + + private static Module oauth2Module(TokenServer tokenServer) + { + return binder -> { + jaxrsBinder(binder).bind(TestResource.class); + newOptionalBinder(binder, OAuth2Client.class) + .setBinding() + .toInstance(tokenServer.getOAuth2Client()); + }; + } + + private static Map getOAuth2Properties(TokenServer tokenServer) + { + return ImmutableMap.builder() + .put("http-server.authentication.type", "oauth2") + .put("http-server.authentication.oauth2.issuer", tokenServer.getIssuer()) + .put("http-server.authentication.oauth2.jwks-url", tokenServer.getJwksUrl()) + .put("http-server.authentication.oauth2.state-key", "test-state-key") + .put("http-server.authentication.oauth2.auth-url", tokenServer.getIssuer()) + .put("http-server.authentication.oauth2.token-url", tokenServer.getIssuer()) + .put("http-server.authentication.oauth2.client-id", tokenServer.getClientId()) + .put("http-server.authentication.oauth2.client-secret", tokenServer.getClientSecret()) + .build(); + } + private static String getOauthToken(OkHttpClient client, String url) throws IOException { @@ -742,6 +780,162 @@ private static String getOauthToken(OkHttpClient client, String url) } } + private static class TokenServer + implements AutoCloseable + { + private final String issuer = "http://example.com/"; + private final String clientId = "clientID"; + private final Date tokenExpiration = Date.from(ZonedDateTime.now().plusMinutes(5).toInstant()); + private final Optional principalField; + private final TestingHttpServer jwkServer; + private final String accessToken; + + public TokenServer(Optional principalField) + throws Exception + { + this.principalField = requireNonNull(principalField, "principalField is null"); + jwkServer = createTestingJwkServer(); + jwkServer.start(); + accessToken = issueAccessToken(Optional.empty()); + } + + @Override + public void close() + throws Exception + { + jwkServer.stop(); + } + + public OAuth2Client getOAuth2Client() + { + return new OAuth2Client() + { + private final AtomicReference> nonceHash = new AtomicReference<>(); + + @Override + public URI getAuthorizationUri(String state, URI callbackUri, Optional nonceHash) + { + // Save the last nonce in order to add it to the next issued ID token + this.nonceHash.set(nonceHash); + return URI.create("http://example.com/authorize?" + state); + } + + @Override + public OAuth2Response getOAuth2Response(String code, URI callbackUri) + { + if (!"TEST_CODE".equals(code)) { + throw new IllegalArgumentException("Expected TEST_CODE"); + } + return new OAuth2Response(accessToken, Optional.of(now().plus(5, ChronoUnit.MINUTES)), Optional.of(issueIdToken(nonceHash.get()))); + } + }; + } + + public String getIssuer() + { + return issuer; + } + + public String getJwksUrl() + { + return jwkServer.getBaseUrl().toString(); + } + + public String getClientId() + { + return clientId; + } + + public String getClientSecret() + { + return "clientSecret"; + } + + public String getAccessToken() + { + return accessToken; + } + + public String issueAccessToken(Optional> groups) + { + JwtBuilder accessToken = Jwts.builder() + .signWith(JWK_PRIVATE_KEY) + .setHeaderParam(JwsHeader.KEY_ID, JWK_KEY_ID) + .setIssuer(issuer) + .setAudience(clientId) + .setExpiration(tokenExpiration); + if (principalField.isPresent()) { + accessToken.claim(principalField.get(), TEST_USER); + } + else { + accessToken.setSubject(TEST_USER); + } + groups.ifPresent(groupsClaim -> accessToken.claim(GROUPS_CLAIM, groupsClaim)); + return accessToken.compact(); + } + + private String issueIdToken(Optional nonceHash) + { + JwtBuilder idToken = Jwts.builder() + .signWith(JWK_PRIVATE_KEY) + .setHeaderParam(JwsHeader.KEY_ID, JWK_KEY_ID) + .setIssuer(issuer) + .setAudience(clientId) + .setExpiration(tokenExpiration); + if (principalField.isPresent()) { + idToken.claim(principalField.get(), TEST_USER); + } + else { + idToken.setSubject(TEST_USER); + } + nonceHash.ifPresent(nonce -> idToken.claim(NONCE, nonce)); + return idToken.compact(); + } + } + + @javax.ws.rs.Path("/") + public static class TestResource + { + private final HttpRequestSessionContextFactory sessionContextFactory; + + @Inject + public TestResource(AccessControl accessControl) + { + this.sessionContextFactory = new HttpRequestSessionContextFactory(createTestMetadataManager(), user -> ImmutableSet.of(), accessControl); + } + + @ResourceSecurity(AUTHENTICATED_USER) + @GET + @javax.ws.rs.Path("/protocol/identity") + public javax.ws.rs.core.Response protocolIdentity(@Context HttpServletRequest servletRequest, @Context HttpHeaders httpHeaders) + { + return echoIdentity(servletRequest, httpHeaders); + } + + @ResourceSecurity(WEB_UI) + @GET + @javax.ws.rs.Path("/ui/api/identity") + public javax.ws.rs.core.Response webUiIdentity(@Context HttpServletRequest servletRequest, @Context HttpHeaders httpHeaders) + { + return echoIdentity(servletRequest, httpHeaders); + } + + public javax.ws.rs.core.Response echoIdentity(HttpServletRequest servletRequest, HttpHeaders httpHeaders) + { + Identity identity = sessionContextFactory.extractAuthorizedIdentity(servletRequest, httpHeaders, Optional.empty()); + return javax.ws.rs.core.Response.ok() + .header("user", identity.getUser()) + .header("principal", identity.getPrincipal().map(Principal::getName).orElse(null)) + .header("groups", toHeader(identity.getGroups())) + .build(); + } + + public static String toHeader(Set groups) + { + return groups.stream().sorted().collect(Collectors.joining(",")); + } + } + private void assertInsecureAuthentication(URI baseUri) throws IOException { diff --git a/core/trino-main/src/test/java/io/trino/server/security/oauth2/TestOAuth2Config.java b/core/trino-main/src/test/java/io/trino/server/security/oauth2/TestOAuth2Config.java index 5f230415ccd3..e7b480df2d95 100644 --- a/core/trino-main/src/test/java/io/trino/server/security/oauth2/TestOAuth2Config.java +++ b/core/trino-main/src/test/java/io/trino/server/security/oauth2/TestOAuth2Config.java @@ -48,6 +48,7 @@ public void testDefaults() .setScopes("openid") .setChallengeTimeout(new Duration(15, MINUTES)) .setPrincipalField("sub") + .setGroupsField(null) .setAdditionalAudiences(Collections.emptyList()) .setUserMappingPattern(null) .setUserMappingFile(null)); @@ -70,6 +71,7 @@ public void testExplicitPropertyMappings() .put("http-server.authentication.oauth2.client-secret", "consumer-secret") .put("http-server.authentication.oauth2.scopes", "email,offline") .put("http-server.authentication.oauth2.principal-field", "some-field") + .put("http-server.authentication.oauth2.groups-field", "groups") .put("http-server.authentication.oauth2.additional-audiences", "test-aud1,test-aud2") .put("http-server.authentication.oauth2.challenge-timeout", "90s") .put("http-server.authentication.oauth2.user-mapping.pattern", "(.*)@something") @@ -88,6 +90,7 @@ public void testExplicitPropertyMappings() .setClientSecret("consumer-secret") .setScopes("email, offline") .setPrincipalField("some-field") + .setGroupsField("groups") .setAdditionalAudiences(List.of("test-aud1", "test-aud2")) .setChallengeTimeout(new Duration(90, SECONDS)) .setUserMappingPattern("(.*)@something") diff --git a/docs/src/main/sphinx/security/oauth2.rst b/docs/src/main/sphinx/security/oauth2.rst index 40f9795ea038..d1eb7936a0d7 100644 --- a/docs/src/main/sphinx/security/oauth2.rst +++ b/docs/src/main/sphinx/security/oauth2.rst @@ -108,6 +108,8 @@ The following configuration properties are available: for more information. * - ``http-server.authentication.oauth2.principal-field`` - The field of the access token used for the Trino user principal. Defaults to ``sub``. Other commonly used fields include ``sAMAccountName``, ``name``, ``upn``, and ``email``. + * - ``http-server.authentication.oauth2.groups-field`` + - The field of the access token used for Trino groups. The corresponding claim value must be an array. Troubleshooting diff --git a/pom.xml b/pom.xml index b6eec55a3014..ba06e3edca2a 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,6 @@ 19.3.0.0 1.14 6.9.0 - 3.141.59 187 2.0.0 2.10.0 @@ -1128,6 +1127,12 @@ ${dep.okhttp.version} + + com.squareup.okhttp3 + okhttp-tls + ${dep.okhttp.version} + + com.squareup.okhttp3 okhttp-urlconnection @@ -1530,54 +1535,6 @@ 42.3.1 - - org.seleniumhq.selenium - selenium-api - ${dep.selenium.version} - - - - org.seleniumhq.selenium - selenium-chrome-driver - ${dep.selenium.version} - - - - org.seleniumhq.selenium - selenium-java - ${dep.selenium.version} - - - commons-logging - commons-logging - - - - - - org.seleniumhq.selenium - selenium-remote-driver - ${dep.selenium.version} - - - commons-logging - commons-logging - - - - - - org.seleniumhq.selenium - selenium-support - ${dep.selenium.version} - - - commons-logging - commons-logging - - - - org.sonatype.aether aether-api diff --git a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/Environment.java b/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/Environment.java index bc24259432a2..17f10ac18b10 100644 --- a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/Environment.java +++ b/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/Environment.java @@ -380,8 +380,9 @@ public Builder addContainer(DockerContainer container) container.withCreateContainerCmdModifier(Builder::updateContainerHostConfig); - if (!container.getLogicalName().equals(TESTS)) { - // Tests container cannot be auto removed as we need to inspect it's exit code + if (!container.getLogicalName().equals(TESTS) && !container.isTemporary()) { + // Tests container cannot be auto removed as we need to inspect it's exit code. + // Temporal containers might exit earlier than the startup check polling interval. container.withCreateContainerCmdModifier(Builder::setContainerAutoRemove); } diff --git a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/EnvironmentModule.java b/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/EnvironmentModule.java index b37d9df21f18..0fa323fb168b 100644 --- a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/EnvironmentModule.java +++ b/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/EnvironmentModule.java @@ -25,7 +25,6 @@ import io.trino.tests.product.launcher.env.common.Kafka; import io.trino.tests.product.launcher.env.common.KafkaSsl; import io.trino.tests.product.launcher.env.common.Phoenix; -import io.trino.tests.product.launcher.env.common.SeleniumChrome; import io.trino.tests.product.launcher.env.common.Standard; import io.trino.tests.product.launcher.env.common.StandardMultinode; import io.trino.tests.product.launcher.testcontainers.PortBinder; @@ -69,7 +68,6 @@ public void configure(Binder binder) binder.bind(HydraIdentityProvider.class).in(SINGLETON); binder.bind(Kafka.class).in(SINGLETON); binder.bind(KafkaSsl.class).in(SINGLETON); - binder.bind(SeleniumChrome.class).in(SINGLETON); binder.bind(Standard.class).in(SINGLETON); binder.bind(StandardMultinode.class).in(SINGLETON); binder.bind(Phoenix.class).in(SINGLETON); diff --git a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/common/HydraIdentityProvider.java b/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/common/HydraIdentityProvider.java index b3adcd84b59c..4903411dcb75 100644 --- a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/common/HydraIdentityProvider.java +++ b/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/common/HydraIdentityProvider.java @@ -19,6 +19,7 @@ import io.trino.tests.product.launcher.env.Environment; import io.trino.tests.product.launcher.testcontainers.PortBinder; import io.trino.tests.product.launcher.testcontainers.SelectedPortWaitStrategy; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; @@ -59,12 +60,14 @@ public void extendEnvironment(Environment.Builder builder) DockerContainer migrationContainer = new DockerContainer(HYDRA_IMAGE, "hydra-db-migration") .withCommand("migrate", "sql", "--yes", DSN) .dependsOn(databaseContainer) + .withStartupCheckStrategy(new OneShotStartupCheckStrategy()) .setTemporary(true); - DockerContainer hydraConsent = new DockerContainer("oryd/hydra-login-consent-node:v1.4.2", "hydra-consent") - .withEnv("HYDRA_ADMIN_URL", "https://hydra:4445") - .withEnv("NODE_TLS_REJECT_UNAUTHORIZED", "0") - .waitingFor(Wait.forHttp("/").forPort(3000).forStatusCode(200)); + DockerContainer hydraConsent = new DockerContainer("python:3.10.1-alpine", "hydra-consent") + .withCopyFileToContainer(forHostPath(configDir.getPath("login_and_consent_server.py")), "/") + .withCommand("python", "/login_and_consent_server.py") + .withExposedPorts(3000) + .waitingFor(Wait.forHttp("/healthz").forPort(3000).forStatusCode(200)); binder.exposePort(hydraConsent, 3000); @@ -74,12 +77,13 @@ public void extendEnvironment(Environment.Builder builder) .withEnv("URLS_SELF_ISSUER", "https://hydra:4444/") .withEnv("URLS_CONSENT", "http://hydra-consent:3000/consent") .withEnv("URLS_LOGIN", "http://hydra-consent:3000/login") - .withEnv("SERVE_TLS_KEY_PATH", "/tmp/certs/localhost.pem") - .withEnv("SERVE_TLS_CERT_PATH", "/tmp/certs/localhost.pem") + .withEnv("SERVE_TLS_KEY_PATH", "/tmp/certs/hydra.pem") + .withEnv("SERVE_TLS_CERT_PATH", "/tmp/certs/hydra.pem") .withEnv("STRATEGIES_ACCESS_TOKEN", "jwt") .withEnv("TTL_ACCESS_TOKEN", TTL_ACCESS_TOKEN_IN_SECONDS + "s") + .withEnv("OAUTH2_ALLOWED_TOP_LEVEL_CLAIMS", "groups") .withCommand("serve", "all") - .withCopyFileToContainer(forHostPath(configDir.getPath("cert")), "/tmp/certs") + .withCopyFileToContainer(forHostPath(configDir.getPath("cert/hydra.pem")), "/tmp/certs/hydra.pem") .waitingFor(new WaitAllStrategy() .withStrategy(Wait.forLogMessage(".*Setting up http server on :4444.*", 1)) .withStrategy(Wait.forLogMessage(".*Setting up http server on :4445.*", 1))); @@ -97,14 +101,22 @@ public void extendEnvironment(Environment.Builder builder) if (isPrestoContainer(dockerContainer.getLogicalName())) { dockerContainer .withCopyFileToContainer( - forHostPath(configDir.getPath("cert")), - CONTAINER_PRESTO_ETC + "/hydra/cert"); + forHostPath(configDir.getPath("cert/trino.pem")), + CONTAINER_PRESTO_ETC + "/trino.pem") + .withCopyFileToContainer( + forHostPath(configDir.getPath("cert/hydra.pem")), + CONTAINER_PRESTO_ETC + "/hydra.pem"); } }); - builder.configureContainer(TESTS, dockerContainer -> dockerContainer.withCopyFileToContainer( - forHostPath(configDir.getPath("tempto-configuration-for-docker-oauth2.yaml")), - CONTAINER_TEMPTO_PROFILE_CONFIG)); + builder.configureContainer(TESTS, dockerContainer -> + dockerContainer + .withCopyFileToContainer( + forHostPath(configDir.getPath("tempto-configuration-for-docker-oauth2.yaml")), + CONTAINER_TEMPTO_PROFILE_CONFIG) + .withCopyFileToContainer( + forHostPath(configDir.getPath("cert/truststore.jks")), + "/docker/presto-product-tests/truststore.jks")); } public DockerContainer createClient( diff --git a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/common/SeleniumChrome.java b/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/common/SeleniumChrome.java deleted file mode 100644 index f0e4268622ca..000000000000 --- a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/common/SeleniumChrome.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed 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 io.trino.tests.product.launcher.env.common; - -import com.google.inject.Inject; -import io.trino.tests.product.launcher.env.DockerContainer; -import io.trino.tests.product.launcher.env.Environment; -import io.trino.tests.product.launcher.testcontainers.PortBinder; -import org.testcontainers.containers.wait.strategy.HostPortWaitStrategy; -import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; -import org.testcontainers.utility.DockerImageName; - -import java.time.Duration; - -import static java.util.Objects.requireNonNull; - -public class SeleniumChrome - implements EnvironmentExtender -{ - private static final DockerImageName CHROME_IMAGE = DockerImageName.parse("selenium/standalone-chrome-debug").withTag("3.141.59-20210804"); - private static final int SELENIUM_PORT = 7777; - private static final Duration STARTUP_TIMEOUT = Duration.ofSeconds(15); - - private final PortBinder portBinder; - - @Inject - public SeleniumChrome(PortBinder portBinder) - { - this.portBinder = requireNonNull(portBinder, "portBinder is null"); - } - - @Override - public void extendEnvironment(Environment.Builder builder) - { - DockerContainer seleniumChrome = new DockerContainer(CHROME_IMAGE.asCanonicalNameString(), "selenium-chrome"); - seleniumChrome.addEnv("SE_OPTS", "-port " + SELENIUM_PORT); - seleniumChrome.addEnv("TZ", "Etc/UTC"); - seleniumChrome.addEnv("no_proxy", "localhost"); - seleniumChrome.setCommand("/opt/bin/entry_point.sh"); - - seleniumChrome.waitingForAll( - new LogMessageWaitStrategy() - .withRegEx(".*(RemoteWebDriver instances should connect to|Selenium Server is up and running).*\n") - .withStartupTimeout(STARTUP_TIMEOUT), - new HostPortWaitStrategy() - .withStartupTimeout(STARTUP_TIMEOUT)); - - // Taken from BrowserWebDriverContainer were it has been said that: - // "Some unreliability of the selenium browser containers has been observed, so allow multiple attempts to start." - seleniumChrome.setStartupAttempts(3); - - portBinder.exposePort(seleniumChrome, SELENIUM_PORT); - - builder.addContainer(seleniumChrome); - } -} diff --git a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/environment/EnvSinglenodeOauth2.java b/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/environment/EnvSinglenodeOauth2.java index 1a27c20a9695..d8bcffbe010d 100644 --- a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/environment/EnvSinglenodeOauth2.java +++ b/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/environment/EnvSinglenodeOauth2.java @@ -20,7 +20,6 @@ import io.trino.tests.product.launcher.env.Environment; import io.trino.tests.product.launcher.env.EnvironmentProvider; import io.trino.tests.product.launcher.env.common.HydraIdentityProvider; -import io.trino.tests.product.launcher.env.common.SeleniumChrome; import io.trino.tests.product.launcher.env.common.Standard; import io.trino.tests.product.launcher.env.common.TestsEnvironment; import io.trino.tests.product.launcher.testcontainers.PortBinder; @@ -41,9 +40,9 @@ public class EnvSinglenodeOauth2 private final ResourceProvider configDir; @Inject - public EnvSinglenodeOauth2(DockerFiles dockerFiles, PortBinder binder, Standard standard, HydraIdentityProvider hydraIdentityProvider, SeleniumChrome seleniumChrome) + public EnvSinglenodeOauth2(DockerFiles dockerFiles, PortBinder binder, Standard standard, HydraIdentityProvider hydraIdentityProvider) { - super(ImmutableList.of(standard, hydraIdentityProvider, seleniumChrome)); + super(ImmutableList.of(standard, hydraIdentityProvider)); this.binder = requireNonNull(binder, "binder is null"); this.hydraIdentityProvider = requireNonNull(hydraIdentityProvider, "hydraIdentityProvider is null"); diff --git a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/environment/EnvSinglenodeOauth2HttpProxy.java b/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/environment/EnvSinglenodeOauth2HttpProxy.java index 6bdfe49df606..679f7b9a567f 100644 --- a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/environment/EnvSinglenodeOauth2HttpProxy.java +++ b/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/environment/EnvSinglenodeOauth2HttpProxy.java @@ -20,7 +20,6 @@ import io.trino.tests.product.launcher.env.Environment; import io.trino.tests.product.launcher.env.EnvironmentProvider; import io.trino.tests.product.launcher.env.common.HydraIdentityProvider; -import io.trino.tests.product.launcher.env.common.SeleniumChrome; import io.trino.tests.product.launcher.env.common.Standard; import io.trino.tests.product.launcher.env.common.TestsEnvironment; import io.trino.tests.product.launcher.testcontainers.PortBinder; @@ -41,9 +40,9 @@ public class EnvSinglenodeOauth2HttpProxy private final ResourceProvider configDir; @Inject - public EnvSinglenodeOauth2HttpProxy(DockerFiles dockerFiles, PortBinder binder, Standard standard, HydraIdentityProvider hydraIdentityProvider, SeleniumChrome seleniumChrome) + public EnvSinglenodeOauth2HttpProxy(DockerFiles dockerFiles, PortBinder binder, Standard standard, HydraIdentityProvider hydraIdentityProvider) { - super(ImmutableList.of(standard, hydraIdentityProvider, seleniumChrome)); + super(ImmutableList.of(standard, hydraIdentityProvider)); this.binder = requireNonNull(binder, "binder is null"); this.hydraIdentityProvider = requireNonNull(hydraIdentityProvider, "hydraIdentityProvider is null"); diff --git a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/environment/EnvSinglenodeOauth2HttpsProxy.java b/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/environment/EnvSinglenodeOauth2HttpsProxy.java index 4cd3e9747de6..4df9422f29ec 100644 --- a/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/environment/EnvSinglenodeOauth2HttpsProxy.java +++ b/testing/trino-product-tests-launcher/src/main/java/io/trino/tests/product/launcher/env/environment/EnvSinglenodeOauth2HttpsProxy.java @@ -20,7 +20,6 @@ import io.trino.tests.product.launcher.env.Environment; import io.trino.tests.product.launcher.env.EnvironmentProvider; import io.trino.tests.product.launcher.env.common.HydraIdentityProvider; -import io.trino.tests.product.launcher.env.common.SeleniumChrome; import io.trino.tests.product.launcher.env.common.Standard; import io.trino.tests.product.launcher.env.common.TestsEnvironment; import io.trino.tests.product.launcher.testcontainers.PortBinder; @@ -42,9 +41,9 @@ public class EnvSinglenodeOauth2HttpsProxy private final ResourceProvider configDir; @Inject - public EnvSinglenodeOauth2HttpsProxy(DockerFiles dockerFiles, PortBinder binder, Standard standard, HydraIdentityProvider hydraIdentityProvider, SeleniumChrome seleniumChrome) + public EnvSinglenodeOauth2HttpsProxy(DockerFiles dockerFiles, PortBinder binder, Standard standard, HydraIdentityProvider hydraIdentityProvider) { - super(ImmutableList.of(standard, hydraIdentityProvider, seleniumChrome)); + super(ImmutableList.of(standard, hydraIdentityProvider)); this.binder = requireNonNull(binder, "binder is null"); this.hydraIdentityProvider = requireNonNull(hydraIdentityProvider, "hydraIdentityProvider is null"); @@ -61,8 +60,8 @@ public void extendEnvironment(Environment.Builder builder) forHostPath(configDir.getPath("config.properties")), CONTAINER_PRESTO_CONFIG_PROPERTIES) .withCopyFileToContainer( - forHostPath(configDir.getPath("cert")), - CONTAINER_PRESTO_ETC + "/cert"); + forHostPath(configDir.getPath("cert/truststore.jks")), + CONTAINER_PRESTO_ETC + "/cert/truststore.jks"); binder.exposePort(dockerContainer, 7778); }); @@ -77,11 +76,6 @@ public void extendEnvironment(Environment.Builder builder) builder.containerDependsOn(COORDINATOR, hydraClientConfig.getLogicalName()); - builder.configureContainer("hydra", dockerContainer -> dockerContainer - .withCopyFileToContainer(forHostPath(configDir.getPath("cert")), "/tmp/certs") - .withEnv("SERVE_TLS_KEY_PATH", "/tmp/certs/hydra.pem") - .withEnv("SERVE_TLS_CERT_PATH", "/tmp/certs/hydra.pem")); - DockerContainer proxy = new DockerContainer("httpd:2.4.51", "proxy"); proxy .withCopyFileToContainer( diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/generate.sh b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/generate.sh index cf662f5e120c..af7b93e2eaa2 100755 --- a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/generate.sh +++ b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/generate.sh @@ -2,5 +2,12 @@ set -eux -openssl req -new -x509 -newkey rsa:4096 -sha256 -nodes -keyout localhost.key -days 3560 -out localhost.crt -config localhost.conf -cat localhost.crt localhost.key > localhost.pem +rm -f truststore.jks + +for name in "hydra" "trino" +do + openssl req -new -x509 -newkey rsa:4096 -sha256 -nodes -keyout "${name}.key" -days 35600 -out "${name}.crt" -config "${name}.conf" + cat "${name}.crt" "${name}.key" > "${name}.pem" + keytool -import -noprompt -alias "${name}" -keystore truststore.jks -storepass 123456 -file "${name}.crt" + rm "${name}.crt" "${name}.key" +done diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/hydra.conf b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/hydra.conf new file mode 100644 index 000000000000..fe9fdf4682eb --- /dev/null +++ b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/hydra.conf @@ -0,0 +1,15 @@ +[ req ] +default_bits = 4096 +prompt = no +default_md = sha256 +x509_extensions = v3_req +distinguished_name = req_distinguished_name + +[ req_distinguished_name ] +CN = hydra + +[ v3_req ] +subjectAltName = @alt_names + +[alt_names] +DNS = hydra diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/hydra.pem b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/hydra.pem new file mode 100644 index 000000000000..ba15db1fb133 --- /dev/null +++ b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/hydra.pem @@ -0,0 +1,80 @@ +-----BEGIN CERTIFICATE----- +MIIEuTCCAqGgAwIBAgIJAOa8Xr8cVD9oMA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNV +BAMMBWh5ZHJhMCAXDTIxMTIyMjA3NDM1MVoYDzIxMTkwNjEyMDc0MzUxWjAQMQ4w +DAYDVQQDDAVoeWRyYTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANFy +KpNoQW3N83gGavUNjvqsJSeVnNpI/76kTesqIQzC7Q/HvK6UbFeZeqc3fD7RcoFo +NvsOl5QORsR3qhFADA2IrPCthF4sqEq0y30/YDxZHDtojY+LdNEE2kcMH15CjoEa +BESu/Y6rmwQ2V653M4IcpOuvQHX7+B7otjQmnht8gv5LgeN0l+BMgGq7DaKXMS/a +jCFG00E+5ilco8a/PakzP/XNfpJiWC/C7eRI8ovmjUgFjY6ixyTABP3rzWM0zgDd +Q9FBUm7lRtTcWwwB7psJ6B1Ibmf4NyvC2YTSFcK3c0KZbLsgb4xcEEcpEiGD6KmH +o8QXO1UYGy3eAZ7/y38Ofo0aNykiLSMHeGZ9n6hR0oTPl3LCJNlHxh3OyRfVgRkW +VntXQRPhRB3L9x7k7Ip9Pjh49orZfjj4GdrJX3/scJcUZCc4KzHPmDjlsgtcPyQY +pSrNfggIxLZERKeT3O5/jIuQAXG7drMb20atAUpQlvAQqBgIRLj9F/W56zg1J+Sr +O0YHnz9/QDqBrhqiF/hP7skzeXcfUyVpSuLRYUFTM46OT8vJzAIbvh9c4grpqd2m +z14JbzTDGPV+tlRPMXP18+1zJ4efFgl46VXZaPiMgVkzbzONNOTyB+cSUfVobBID +ian7Hs62gR4hTu1upcSFwLlnYBqOBQbH5l1mATrtAgMBAAGjFDASMBAGA1UdEQQJ +MAeCBWh5ZHJhMA0GCSqGSIb3DQEBCwUAA4ICAQCD5GmzbLlYqfpv5uxSJQqvLHDT +1m6RWx0Ym/h/wNJR3nh68K/GKDPUh0EV5TUWQUg9rr0aB1ozV2lJTK2e3OQN+qDp +CyHSgt+tw/ir/DfAqeCmadvXoXwOs52UQMm9YDq4KU7bcIGVTT+LG/JgFTurS94n +PTdXbmC16PJyOR8KC7WlxmU4VYyv4MvsWUuzndoWigu8IjrlclbAPN04hBx68YII +tcS/X5fjTDrtLeyCqoa5alsmReiY7uIxI+aZPY8AZw3mhM2ZqnFE4ThY+Rsulp4X +kWBJSrLU+ahU3YvddQCMoAbfrJo/PBb2S7MO6dAerlTe12RRtA914wghueuA1zEj +Y6Rauu0pDWj2f5Ga7O0nisuFI8XaaMKlVAKfnSadpK8iU1jbU+GIDJ5ZM/fIF7mE +gKPxWL6NoFgy2psFlSjwgk7X3wo1MPxy9vtGGzZHGqKhNy7FNjrRLStwzaA8t3Py +vSltFEAjOzT0kyLCunWd8KKloUTVkQ3aCsy2YCzYlrpXcMyszqTP/PllWyaPMGLB +/zi9Vdu2fY+881SaeePO6Shazv5mY8Q2Ed6in79OTGp4ioLbvYmiyuJ/fRzBYJit +NeoWNt2mrZgY2nn7+L9zA3W32+YNILB7/MjBmwokhxbHF6dbtn1MsnUF7qd0aCkD +aQ3dA9Anu/PASQCddw== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +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 +4N+nzawlz9SrYXr6fQUPqdRex41H +-----END PRIVATE KEY----- diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/localhost.conf b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/localhost.conf deleted file mode 100644 index 11be13d10710..000000000000 --- a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/localhost.conf +++ /dev/null @@ -1,19 +0,0 @@ -[req] -default_bits = 4096 -prompt = no -default_md = sha256 -x509_extensions = v3_req -distinguished_name = dn - -[dn] -C = US -ST = California -L = Palo Alto -O = PrestoTest -CN = PrestoTest - -[v3_req] -subjectAltName = @alt_names - -[alt_names] -DNS.1 = hydra diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/localhost.pem b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/localhost.pem deleted file mode 100644 index cafb06346dee..000000000000 --- a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/localhost.pem +++ /dev/null @@ -1,83 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgIJANciS7odijt6MA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV -BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlQYWxvIEFsdG8x -EzARBgNVBAoMClByZXN0b1Rlc3QxEzARBgNVBAMMClByZXN0b1Rlc3QwHhcNMjEw -NTI2MTIwNDA5WhcNMzEwMjIzMTIwNDA5WjBgMQswCQYDVQQGEwJVUzETMBEGA1UE -CAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJUGFsbyBBbHRvMRMwEQYDVQQKDApQcmVz -dG9UZXN0MRMwEQYDVQQDDApQcmVzdG9UZXN0MIICIjANBgkqhkiG9w0BAQEFAAOC -Ag8AMIICCgKCAgEAxSzRwKshIyVwtRkOQCg2VjaD2woUyqxljbOPYOLNt2NdBa5/ -LMJ+LaHwsmVyW8l8EGLdp7EGRNjZfG4ZezZbMTRf4RkrVcDAgFdMONjNmM3iyLi+ -ryPDzEQFnI4Z2dJ3ZpsdDATbcWPPv1qyvI0vOyYrVHHByYCaKOTrzfzV9sssXMR8 -osy4aVjP5SOOLMKg99bAeWMCTDTYJlXc7ROba+N6OYEDR6a1vefXI4hc4dQy18SZ -/rFqvgcf+rqlz+PL+kNjPJ2uBAvcDF3e0fEMOn8yhPDvrp3Lzso1wwgAFZCE7Cv2 -hz0pCqYy6hMUSl4HqZLj0WlPDTOobKSADoQkHfjEGhCtThj9CWwGly7aeQdk+roI -VRDXcYLeJXA/xSzTPtWO4wkjX9VMcwWrFYDuycqxyfXvKxGPHsY3oRqbgW5RgvOh -sIPa7Yu3oc998h6QyMDO6YPseKfRULuOse7ITUTRNPV0A4eztOne5/ZemEiRYzwH -N8+r8zsdz5m47B0+8ZNpiiBgy9sTCNs2DKy50HZNJ/D5CQOwW56CfV5NHAXhocAE -aSmbSPOs0Wz+wDR+5cs9B6pKZd6BqyOJz+/+2tPQ30OpGbjyWgRoK9cHld82CiWY -+FgTFQaBK5OrL4puaGY+mus8C31i6HD5r+ECmkK+iG9z1K23ifDYI1opAG8CAwEA -AaMUMBIwEAYDVR0RBAkwB4IFaHlkcmEwDQYJKoZIhvcNAQELBQADggIBALW9IvOs -DNCrJrx2ZJN0N+EMY5kOXFtrfQPgz5OWYz0TNBIbEjNWGRYyrYNyijdzgnIeEn3P -BQ+0jl6O2sbSF9vkKgwCH9iH6oDtU4bApqGz8W5uFyM3kgS31C7ZJSCu/+KtsKwv -q7o3g5jSLW6Wgn+abJIoljn+/Z5vHn+81tWjxUfY8gwhtw8mk9vrS6mVuMhYfuoi -4eZ7pew/8mYdfHhwRdBAEZN4+ovNgb1GZDk4s2NWwOGS0WpUDfAuXVeZ2GzOPVbR -YEbaSwrGh+M2K+Vg1MEgkPmRCY3drZOJd6wcCkJVE6sUsp6UIKzFdDrSFU2mvyhS -MJU/JC+0rPFpjsDe+VvAEbHTJ0nx37hh6igpZuSJH39O9oKjox3HKItf6OtGj9K1 -1XPyWsBQgZdyqh8nFFrf8n1qnfeJR6wJpYd1cW3oJuNgbVtmyvTOMdNHdII1tKv5 -lfgB4TCoKJpEiYYZlTtHIiB8NyUy4PpVCfmfe7tfIKcUV29oa1ZJRH0Fq3l/ywlQ -WuRCYHw6vEOCR17TiLRN02NMU6QYQKFlK8zFgempKf6b943MYQ9EBYC4Z3Xuw7R3 -qozE9UDK/7cGTH0Vy1Cpt3T857G0FjivG/KQFqtM6V4om9PsX052w2kabrtYw7th -vRDDiUuChbW5L/Bn+N+HMDq9phsfcI5/zBry ------END CERTIFICATE----- ------BEGIN PRIVATE KEY----- -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 -bVAoDxTHIF++oefZSmn2rZBOBCtW ------END PRIVATE KEY----- diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/trino.conf b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/trino.conf new file mode 100644 index 000000000000..a70f27181b85 --- /dev/null +++ b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/trino.conf @@ -0,0 +1,15 @@ +[ req ] +default_bits = 4096 +prompt = no +default_md = sha256 +x509_extensions = v3_req +distinguished_name = req_distinguished_name + +[ req_distinguished_name ] +CN = presto-master + +[ v3_req ] +subjectAltName = @alt_names + +[alt_names] +DNS = presto-master diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/trino.pem b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/trino.pem new file mode 100644 index 000000000000..42904fb19baf --- /dev/null +++ b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/trino.pem @@ -0,0 +1,80 @@ +-----BEGIN CERTIFICATE----- +MIIE0TCCArmgAwIBAgIJAO4k4YwG5hr8MA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV +BAMMDXByZXN0by1tYXN0ZXIwIBcNMjExMjIyMDc0MzUyWhgPMjExOTA2MTIwNzQz +NTJaMBgxFjAUBgNVBAMMDXByZXN0by1tYXN0ZXIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC1ioarBcMyp88h4Cp8Dw6me9KFcvnhuadIkEfwwh/QRzk6 +Zb4lwUlJduUo72nUVkklAWpuLWFwoeDDWrrttJSTtXfs0YtQzbLLY+N+NJcrSO9K +Q9KMxOSevsVvqokvq7cKOcwOuHMxLZ+p48g+XQvjTuhOTXRbJSlXLpGi/z2EC+RM +QRrdbbwy6ubgtIJWK9GGS/FtHXIglhNPZCA5dPg9ljM+LSZkxgr1X5DqLuPamF6V +G7eZDAPJ59aEljIFS0NC0hSDydaWtVuQ+cuee/Nbk/Tk0jnK+VFPnhWhPHisOE3y +3cF5wXXSd8ScNcYsj6LjJ8KwNkT+BUEWjRTaYOjahggHUW4ZTDeOC9w6lFpGf5ag +gstRj4d1TjTAxAq8ZSvWe1wgJiBxkRotM+R1eDcAISxh2+Dj9ZqLiL6wTkiZOGAx +9lxwlielnwsuxpVAko+4R+GqXw2sbREppSZwVKtkIAsaa9soWG2YBf+7G7zr9F/f +i24tBDvTNruTXN0X7hk9lujj2sVb2zv4lo/gy1FOQv4LfIr6/8jmmsRWAOuyril8 +DyItRCarcd0FwbHyQgVijsNjdSkpUZ+PCmPjKRfUFIvbyCTltedb7xXLyBD9tvzC +oYeqMgDPglNFS2YzMzymghegQm7ZzKSeTmvGQGOe4gph0r18IQ/IckzheAnYswID +AQABoxwwGjAYBgNVHREEETAPgg1wcmVzdG8tbWFzdGVyMA0GCSqGSIb3DQEBCwUA +A4ICAQB/Mtfa+32FT7rrxLYdzoW2mCXH7I0lXnjXM7EXo6oeO8rrNWQboYn2KGUy +7nPlnwt9zR8p7f4ERpgwYITHZruv3NnBnnRm2Exrg+gjH5WTPAqPoBlZtDtw1fQz +eyn3SXe1J2xBiec4HUadkf/nqOsx3BWl59mvL8DaRlT/CCQmWG89G6TRIcIAev3W +qZUOd/NuXY32iuRMv5j2CdwFKRIAhvldLrqzvD3U6imb/YOnoDz1omsXe4L6xcgS +OJH1hhxMjBdYSkrcGiy5N5Oe7JL45kIvxi518O3c8CvdZdWc9dudzpl/Q9clRabd +Q0v3jSdeXiZNl6UgxK+9IYx6r1cOM4eKjqYSsmzOhrcREU3LUY/HfDatjqCdKjPz +pvM1zCzr3Wf4/R7Ene1zdq7SNlnuWy2p1FoDLtDmYPwV1jSMduemMZPAp5rYIA6r +Wn65GVOy3DAjK073ICH+0BA0kftXXIm/3scj4Y5iFFFkGq9UvA+gdScIeBuSNYrm +Q40IaEDDCH/ROMo+ieBPtFbFZoDcqT8t5Ba52cjDtmmTR8AbBSAQOee4cef/eijI +0gEm97Fu17kHIF6uZvOLI/zMY91lhikTviuSp8OSpsFrphWB4JNtZhdYu2lKkqMs +00rnB0zHg4sXqvonEzrmvdTI2pD3lFLJTaD4XtOiEtaMkhpeoQ== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +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 +ag1idl6/CvSJuJ2XJErJzXTcFTnuFNo= +-----END PRIVATE KEY----- diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/truststore.jks b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/truststore.jks new file mode 100644 index 000000000000..f9ab80eac63d Binary files /dev/null and b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/cert/truststore.jks differ diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/login_and_consent_server.py b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/login_and_consent_server.py new file mode 100644 index 000000000000..d1a08f456170 --- /dev/null +++ b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/login_and_consent_server.py @@ -0,0 +1,75 @@ +import json +import os +import ssl +from http.server import BaseHTTPRequestHandler, HTTPServer +from typing import Dict, Any +from urllib.parse import urlparse, parse_qs +from urllib.request import Request, urlopen + +HYDRA_ADMIN_URL = os.getenv("HYDRA_ADMIN_URL", "https://hydra:4445") +PORT = os.getenv("PORT", 3000) +SSL_CONTEXT = ssl.create_default_context() +SSL_CONTEXT.check_hostname = False +SSL_CONTEXT.verify_mode = ssl.CERT_NONE + + +class LoginAndConsentServer(BaseHTTPRequestHandler): + def do_GET(self): + params = parse_qs(urlparse(self.path).query) + if self.path == "/healthz": + self.send_response(200) + if self.path.startswith("/login"): + self.accept_login(params) + return + if self.path.startswith("/consent"): + self.accept_consent(params) + return + self.send_error(404, "Not found") + + def accept_login(self, params: Dict[str, list[str]]) -> None: + login_challenge = params["login_challenge"][0] + with urlopen(Request( + method="PUT", + url=HYDRA_ADMIN_URL + "/oauth2/auth/requests/login/accept?login_challenge=" + login_challenge, + headers={"Content-Type": "application/json; charset=UTF-8"}, + data=json.dumps({"subject": "foo@bar.com"}).encode()), + context=SSL_CONTEXT) as response: + self.send_redirect(response) + + def accept_consent(self, params: Dict[str, list[str]]) -> None: + consent_challenge = params["consent_challenge"][0] + consent_request = self.get_consent_request(consent_challenge) + with urlopen(Request( + method="PUT", + url=HYDRA_ADMIN_URL + "/oauth2/auth/requests/consent/accept?consent_challenge=" + consent_challenge, + headers={"Content-Type": "application/json; charset=UTF-8"}, + data=json.dumps({ + "grant_scope": consent_request["requested_scope"], + "grant_access_token_audience": consent_request["requested_access_token_audience"], + "session": { + "access_token": { + "groups": ["admin", "public"] + } + }}).encode()), + context=SSL_CONTEXT) as response: + self.send_redirect(response) + + @staticmethod + def get_consent_request(consent_challenge: str) -> Dict[str, Any]: + with urlopen(Request( + method="GET", + url=HYDRA_ADMIN_URL + "/oauth2/auth/requests/consent?consent_challenge=" + consent_challenge), + context=SSL_CONTEXT) as response: + return json.load(response) + + def send_redirect(self, response): + body = json.load(response) + self.send_response(302) + self.send_header("Location", body["redirect_to"]) + self.end_headers() + + +if __name__ == "__main__": + server_address = ("", PORT) + httpd = HTTPServer(server_address, LoginAndConsentServer) + httpd.serve_forever() diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/tempto-configuration-for-docker-oauth2.yaml b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/tempto-configuration-for-docker-oauth2.yaml index 046df1fed050..a44081af00ba 100644 --- a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/tempto-configuration-for-docker-oauth2.yaml +++ b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/common/hydra-identity-provider/tempto-configuration-for-docker-oauth2.yaml @@ -10,5 +10,5 @@ databases: SSLTrustStorePath=${databases.presto.https_keystore_path}&\ SSLTrustStorePassword=${databases.presto.https_keystore_password}&\ externalAuthentication=true" - https_keystore_path: /docker/presto-product-tests/conf/presto/etc/presto-master.jks + https_keystore_path: /docker/presto-product-tests/truststore.jks https_keystore_password: '123456' diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-http-proxy/config.properties b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-http-proxy/config.properties index 977ad331c115..eb688dd78ad9 100644 --- a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-http-proxy/config.properties +++ b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-http-proxy/config.properties @@ -12,8 +12,7 @@ web-ui.enabled=true http-server.authentication.type=oauth2 http-server.https.port=7778 http-server.https.enabled=true -http-server.https.keystore.path=/docker/presto-product-tests/conf/presto/etc/presto-master.jks -http-server.https.keystore.key=123456 +http-server.https.keystore.path=/docker/presto-product-tests/conf/presto/etc/trino.pem http-server.authentication.oauth2.issuer=https://hydra:4444/ http-server.authentication.oauth2.auth-url=https://hydra:4444/oauth2/auth http-server.authentication.oauth2.token-url=https://hydra:4444/oauth2/token @@ -21,5 +20,6 @@ http-server.authentication.oauth2.jwks-url=https://hydra:4444/.well-known/jwks.j http-server.authentication.oauth2.client-id=trinodb_client_id http-server.authentication.oauth2.client-secret=trinodb_client_secret http-server.authentication.oauth2.user-mapping.pattern=(.*)(@.*)? -oauth2-jwk.http-client.trust-store-path=/docker/presto-product-tests/conf/presto/etc/hydra/cert/localhost.pem +http-server.authentication.oauth2.groups-field=groups +oauth2-jwk.http-client.trust-store-path=/docker/presto-product-tests/conf/presto/etc/hydra.pem oauth2-jwk.http-client.http-proxy=proxy:8888 diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/create-certs.sh b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/create-certs.sh old mode 100644 new mode 100755 index 4e910b8fa644..d83865149be6 --- a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/create-certs.sh +++ b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/create-certs.sh @@ -2,14 +2,12 @@ set -eux -for i in hydra proxy; do - echo $i +cp "$(dirname "$0")/../../../../common/hydra-identity-provider/cert/truststore.jks" truststore.jks - # Generate private key and certificate - openssl req -new -x509 -newkey rsa:4096 -sha256 -nodes -keyout $i.key -days 3650 -out $i.crt -config $i.conf - cat $i.crt $i.key > $i.pem +# Generate private key and certificate +openssl req -new -x509 -newkey rsa:4096 -sha256 -nodes -keyout proxy.key -days 36500 -out proxy.crt -config proxy.conf +cat proxy.crt proxy.key > proxy.pem - # Create truststore and import the cert. - keytool -keystore truststore.jks -alias $i -import -file $i.crt -storepass changeit -noprompt - rm $i.crt $i.key -done +# Create truststore and import the cert. +keytool -keystore truststore.jks -alias proxy -import -file proxy.crt -storepass 123456 -noprompt +rm proxy.crt proxy.key diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/hydra.conf b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/hydra.conf deleted file mode 100644 index 11be13d10710..000000000000 --- a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/hydra.conf +++ /dev/null @@ -1,19 +0,0 @@ -[req] -default_bits = 4096 -prompt = no -default_md = sha256 -x509_extensions = v3_req -distinguished_name = dn - -[dn] -C = US -ST = California -L = Palo Alto -O = PrestoTest -CN = PrestoTest - -[v3_req] -subjectAltName = @alt_names - -[alt_names] -DNS.1 = hydra diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/hydra.pem b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/hydra.pem deleted file mode 100644 index 13d1b030a66c..000000000000 --- a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/hydra.pem +++ /dev/null @@ -1,83 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgIJAMB9iM7Mrn+jMA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV -BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlQYWxvIEFsdG8x -EzARBgNVBAoMClByZXN0b1Rlc3QxEzARBgNVBAMMClByZXN0b1Rlc3QwHhcNMjEx -MTI1MTQwMjQzWhcNMzExMTIzMTQwMjQzWjBgMQswCQYDVQQGEwJVUzETMBEGA1UE -CAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJUGFsbyBBbHRvMRMwEQYDVQQKDApQcmVz -dG9UZXN0MRMwEQYDVQQDDApQcmVzdG9UZXN0MIICIjANBgkqhkiG9w0BAQEFAAOC -Ag8AMIICCgKCAgEArE9uGiDuoN8aQeEBzLk+AXi9VdTsBSwXxZqXET3Kojm706q8 -+mIrYIWgTbw5ZmRoE1wvJ15iOdOsPm9m1knhS02ygUs4s8H7wAa5o4ciUvCJFdDB -FXHgZ7wxkeTCmZiGAORDRiaZAs4YIO898xpQ11L6c+X/lcyhCOqQEZaNvpEioPxo -DYZvBLcUUFYHYB2bSFmjLiVYUnzsopTJwzw50ll4PgQJSHrT5vNrIWRGzZeqi+lr -IFYKpgAOeUxGbimDhs524M+r5GRlZIvnhPL4/iaOKVrTLbhF7spBMoFR/fsChvMf -WKDZTU8jbeZWb/42p33eR51A50U+xfSqthmvH4Z4xXpxcgYfNi3/9yXK5Mo+rv1U -ReP64pzczGUzyDkVuEn9arT/kdZHcNPtJdmmGQq1W+p36K+e9jbM7y0ZaJ9L8K+2 -xoJ5WPvi6ar6ahsVOLMR5VWkF0QcMaEOLGe86bB0/UagrdQK08hL7N0B5pT93c0V -EpnEWncFmBd7nozm7IisH/iOuG3/C30IRUxC8rngrJD3wrypdCwg3cZ+0HiXEGhz -Q+TVehVRtbNlWM3EV3mB7LItRmYtgQhK8t3dARy9X3j+gXMuQpVXZHlbML+xHiEM -Yx4YfliYcYBNc9LKG58iTsRJxYSXPrOaqDwjnhm5KelBCZPoAcJCq7J3J0cCAwEA -AaMUMBIwEAYDVR0RBAkwB4IFaHlkcmEwDQYJKoZIhvcNAQELBQADggIBAEkQjFAN -g3UYaO/iMJwqeMsasetklHdMe86TD0MsJ3Tp7NpGPlUJ9zqW3jQhvmU5EYaY0cVl -2x04R1C0ByBMlucVB+fdEMvvMVHsBtaeDra2oNBAZILj4rNWEdjcT2f6pFl3xuB/ -wrbEmiiYrT+n2pedvfy84ov8Wo2ipP+Pdl2epRVOGjqeiN2Xxept+5uArGo0icp9 -gPaBZ+1TzjVQ8R1bhJTq8tlCD+nGISG9PQtkBwFLSX6q7Cso9AnUe5KEszNFngjY -JAML2gD6+K2Nd7VZEm78j7sxIGVB50WD619dJ8vvWpnJsDv/MpsJRj1b4gaKfLpd -622VkFeFZfmASbOK9+tP0ZcYwOiJuhbGbA2tg/RCFJo+UJZi34J8Pg2tmI7JvpGH -LVUqEAqNkcVuF2RitZ/h4KjuLOAgPfRe4uYavGJYXy84AyCxpwIXxchZ+P2RHIrU -dAD2VbTj+zjlO4fcKSfjzOi+RHOREMlQBFPDOIssZvbAQbW2wD9g66P4Yu3jl7wO -fDcJg6Ux0dRoBCeUPCWPqndYOgJ0DSv2cYCv/HcI07hA1xH38nxZrxPfKYAAFhXQ -vQy/T9Bb96KlpBwEQZN2ge6GH3k0Twyf1XhCiftHu5OHjW0fudOgPxqHJMPJ2VyS -QXvNn3LrsEyKBTNttmhjKnFahHKMfL332odr ------END CERTIFICATE----- ------BEGIN PRIVATE KEY----- -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 -7ZAmQq6tNRH2Nd/K9JtkFHsG5v8tpz8= ------END PRIVATE KEY----- diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/proxy.pem b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/proxy.pem index 5a6c9b68fee9..b795e7dd6868 100644 --- a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/proxy.pem +++ b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/proxy.pem @@ -1,83 +1,83 @@ -----BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgIJAPKFfaGVNxY0MA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV +MIIFWTCCA0GgAwIBAgIJAJGKeIrKYuZIMA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlQYWxvIEFsdG8x -EzARBgNVBAoMClByZXN0b1Rlc3QxEzARBgNVBAMMClByZXN0b1Rlc3QwHhcNMjEx -MTI1MTQwMjQ0WhcNMzExMTIzMTQwMjQ0WjBgMQswCQYDVQQGEwJVUzETMBEGA1UE -CAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJUGFsbyBBbHRvMRMwEQYDVQQKDApQcmVz -dG9UZXN0MRMwEQYDVQQDDApQcmVzdG9UZXN0MIICIjANBgkqhkiG9w0BAQEFAAOC -Ag8AMIICCgKCAgEAz0lMy27eEa1cTuxE0PG4oc2eZOiijEHk+eP7aRf3DAfUnYAd -WCwu69qxV4Nb5mQQKRz/Gr1mrHjaYTIJirFYY4zNUUfxd6gPzyX6CSe3srL5QQIZ -HxT+AJcVOaIwARVhiu2hBRWdX50jS7ONPA8+ccSAeY40Xh+UtWm35TUOxfZc320d -03CjVcWwM5ygzaRmVtwQAjWZ9MfJ8U5NohdVspS7SN8gssI4KYd15MSceJeabvzq -b142aIMnmhVLvx27X6pub2IwmT5rmhDsxxXciRBUF5mGNhcS25lYycqJ0U7fZzbt -qA7sJidup5e3mPXdjmQgloeekDovHWxqp1qLVyNR2+pKN0pfVsbFR6oXrafU63G7 -ZMOkiyk+sii5WAmygyuRBGSsc/gPz9Ke6UVPAY428RNzGAKiMp2tES3byue5p8IK -bop1imo2xBIekIVjxmUP4s/QJ7VQAYmHIhEvRhNDKEg+18ZHcDTBYKGNx0aYtwrX -4nYtdLQ5mMmunOe2X2X41LWCB0vxP8cMnSmuhlWp4m57tSmDsjx3hozCOhDaV6Fa -ykzwzcnE3Dki6zW2d29r1pAd627UhWyE6Aqxk3vO6qorG8QTzU7UmGMGcRfALs+u -IHPOXXqt/U+6MhYdrJi/BcP8UQXjE0YbW3NBro0q/QwtRSoe3tqX8+DhR5cCAwEA -AaMUMBIwEAYDVR0RBAkwB4IFcHJveHkwDQYJKoZIhvcNAQELBQADggIBAG6jWgW8 -2MGNy8HEuKgY7LQTD3CqyaRrG3qpzz7YfXd0wJL6BA/TNOu7AMHMsoAFQn9Ua5t6 -H1lh0eFO7r3zovJRlaJPqwEw54EbgcimF1vOJNklWovPfuFopC1p8Q0pnA/2Qrpe -kEBrX9LUhDRT143UQ0e43EhT0MBXBtrUQhw7zgE88eh37nLz/HyS9UFFkFn1YmTY -czXfXcRVR1TB6EY10x2NQb889iHRzT3Pt23WwNcm6iKMkDNTn6HgmNUcE9db4fPV -bshvtb1HGLmZ/T8Se23XK0Wt5nLZ4n++sWyfMHQRsPALNZjCpxjT7sgITA4R4ikh -5WqTKjO+QCO8w+mQlVjBKbu7s4PVvj6VrsJzcE2TnmQedkqs29sEcpBW64R5B6gP -7ujoJwzYVQoAtK1RhwQglWxPcx7PbMvEQpiutnZ/DFo785EkfB3ha+NdDthoNod+ -4wtnE3IRdh/4lJN1bZtkVEEKyaToQe0veRXGtsmzUr4e2kW3ii/1usknkkSq+bC/ -JTDpRbVD1OIDx8q6TfVkU4r5egYzfYogGOXtZrr8gYzjbhBFZwGNS8ro1KNmpwxo -26RqbWOjmkRLO5tJPhUDBg9IxG5RSasAA8Zqn5IHh2G85sIyJ1rXkpe0aprC7uRY -YAdfq/7sPdurnpu8PXvw0/DVxd5np2x6qYp6 +EzARBgNVBAoMClByZXN0b1Rlc3QxEzARBgNVBAMMClByZXN0b1Rlc3QwIBcNMjEx +MjIzMDc0ODUwWhgPMjEyMTExMjkwNzQ4NTBaMGAxCzAJBgNVBAYTAlVTMRMwEQYD +VQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlQYWxvIEFsdG8xEzARBgNVBAoMClBy +ZXN0b1Rlc3QxEzARBgNVBAMMClByZXN0b1Rlc3QwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC+j+uWvhNcqkEOfFu4ALDsy1r1osYEfWwD91jqaZy50wCP +YpOwMWbvAWvky+LB6ibJuEqjVfdqFicQvOWAJs1kWq86igKVybjQT/J8bv8cYtKJ +B5KwrfUNyU5g2nDz4v6O9xKO3+UE4WgWNoROGM54+jCNJixRWQDrVJp6ZcIKYcK1 +mdXATiZ1Df/P2YTXJJUdeUvDAwuR7YNX6GrYMsRH/et3vy1t7ySjni5otvdwd93v +H9OeUD9nr1qxHgaNcfH7sQU5pAERlXsFg8/w4nRufPK0iAOTV1P6YASXDAlRj9AW +TCySqvYCvGswRrLYb9YSWqXn//UvCk1UuAoFTZ16Mm0IxonWbMr74duOb0JUH1ZB +4S/TO4hc7cDQQI3Z+/B3q3uHsw5BiCAoZ04PW88x5UQfjTu+SGCG+zHXIINkdu++ +/F28AlAXzAskEDQjw2e4CoeF0LGCWZS1XSTMXNOdCG/6YeJfBu29iPa2nOA2+xDV +NcURdZb/nFY4LPv41z1EXLdTzo9g6sMZ/oQSU/z72Q12H2x2NHTTbXWExJTZuyL0 +YkL78/RV64Fox6ABm5U0sNVNaINW9iL+p6suuP3VtrxZpNmEjt0Ep16j+04BQ/P1 +tkEI7D9n6g3XImaPWjpS674ESRFN/1lPUseilPzhJuGlJ2ahtsYgGTk/tqjbxwID +AQABoxQwEjAQBgNVHREECTAHggVwcm94eTANBgkqhkiG9w0BAQsFAAOCAgEAQ1eY +T+GTohsYLD3OQPEw9qMPIs+WOhdG2z9jO0y82LfykVnXsv8MhlYZ26uinu2QLLmc +Ufdz63CAU1d5jIRyLJ160dpALWuF2v9Dh7dKLarIlFVs9k6fkN2c1Xw3do1d1OqU +d4lNU5Rc1+lFbROi06OBavAVqRVzl00JR2krRqX+PZaHD6EGUC00n120R+Vse3E+ +Ed+cAb3lfy8TOE6psahEHX+kDW3rwR/amY4Hh8ZIlSlEShnoi4ruvrxClT7OfPxQ +2DM7MM62TFwjVRq8rsc2HfuAYTvwOE5wXeIVW+TwflpWjivTeQuBDqAzA4v1Ady0 +2oj/x1TmMgLs6htn5fwUKQ8YGy2IzbgVkugYO7/1hVfXGHS4cEtkDQFAOLnlTjVv +QbxwYS8xaRINI8jXIMAQR2TqEDIGCC2W5ZlPemSGwENaAc71S8GHWtf25TEpuepK +B6HwoF687Vd5utDW/ICqHjjzYey1DkXgQJ/5sCT+NhSS5C6xTeL5wbSLfDB/YhPV +EaChOG5pedvp+22Gz9BMzyEDQh58Qce7EiCAh76lsz0QBXE+OhVwTV2ZIS+w9fY7 +EOUeObHyYrT3Yqdl7ETuPxIxNB6MpxXi7w0qGgtpu57Cz/+04vLDM9reij2hEBwW +e0Mw1IhmXOkVga8UlCzctkUrFp+2Da6z/KX3gk0= -----END CERTIFICATE----- -----BEGIN PRIVATE KEY----- -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 -H5XnZiQqrccTT4vob9YGhsTMx4239gY= +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 +WeqKrlt4TvvXTkV/ic8cWtqnkgkD -----END PRIVATE KEY----- diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/truststore.jks b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/truststore.jks index 46fce42b7d9d..1c626c72be4f 100644 Binary files a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/truststore.jks and b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/cert/truststore.jks differ diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/config.properties b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/config.properties index c637bd72bb92..d6162c783551 100644 --- a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/config.properties +++ b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2-https-proxy/config.properties @@ -12,8 +12,7 @@ web-ui.enabled=true http-server.authentication.type=oauth2 http-server.https.port=7778 http-server.https.enabled=true -http-server.https.keystore.path=/docker/presto-product-tests/conf/presto/etc/presto-master.jks -http-server.https.keystore.key=123456 +http-server.https.keystore.path=/docker/presto-product-tests/conf/presto/etc/trino.pem http-server.authentication.oauth2.issuer=https://hydra:4444/ http-server.authentication.oauth2.auth-url=https://hydra:4444/oauth2/auth http-server.authentication.oauth2.token-url=https://hydra:4444/oauth2/token @@ -21,7 +20,8 @@ http-server.authentication.oauth2.jwks-url=https://hydra:4444/.well-known/jwks.j http-server.authentication.oauth2.client-id=trinodb_client_id http-server.authentication.oauth2.client-secret=trinodb_client_secret http-server.authentication.oauth2.user-mapping.pattern=(.*)(@.*)? +http-server.authentication.oauth2.groups-field=groups oauth2-jwk.http-client.trust-store-path=/docker/presto-product-tests/conf/presto/etc/cert/truststore.jks -oauth2-jwk.http-client.trust-store-password=changeit +oauth2-jwk.http-client.trust-store-password=123456 oauth2-jwk.http-client.http-proxy=proxy:8888 oauth2-jwk.http-client.http-proxy.secure=true diff --git a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2/config.properties b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2/config.properties index 120c6068b157..67d9be99b3f4 100644 --- a/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2/config.properties +++ b/testing/trino-product-tests-launcher/src/main/resources/docker/presto-product-tests/conf/environment/singlenode-oauth2/config.properties @@ -12,8 +12,7 @@ web-ui.enabled=true http-server.authentication.type=oauth2 http-server.https.port=7778 http-server.https.enabled=true -http-server.https.keystore.path=/docker/presto-product-tests/conf/presto/etc/presto-master.jks -http-server.https.keystore.key=123456 +http-server.https.keystore.path=/docker/presto-product-tests/conf/presto/etc/trino.pem http-server.authentication.oauth2.issuer=https://hydra:4444/ http-server.authentication.oauth2.auth-url=https://hydra:4444/oauth2/auth http-server.authentication.oauth2.token-url=https://hydra:4444/oauth2/token @@ -21,4 +20,5 @@ http-server.authentication.oauth2.jwks-url=https://hydra:4444/.well-known/jwks.j http-server.authentication.oauth2.client-id=trinodb_client_id http-server.authentication.oauth2.client-secret=trinodb_client_secret http-server.authentication.oauth2.user-mapping.pattern=(.*)(@.*)? -oauth2-jwk.http-client.trust-store-path=/docker/presto-product-tests/conf/presto/etc/hydra/cert/localhost.pem +http-server.authentication.oauth2.groups-field=groups +oauth2-jwk.http-client.trust-store-path=/docker/presto-product-tests/conf/presto/etc/hydra.pem diff --git a/testing/trino-product-tests-launcher/src/test/java/io/trino/tests/product/launcher/local/TestManuallyJdbcOauth2.java b/testing/trino-product-tests-launcher/src/test/java/io/trino/tests/product/launcher/local/TestManuallyJdbcOauth2.java index 397ea606189e..8c474d9f9239 100644 --- a/testing/trino-product-tests-launcher/src/test/java/io/trino/tests/product/launcher/local/TestManuallyJdbcOauth2.java +++ b/testing/trino-product-tests-launcher/src/test/java/io/trino/tests/product/launcher/local/TestManuallyJdbcOauth2.java @@ -48,7 +48,7 @@ public void verifyEtcHostsEntries() /** * This test is here to allow manually tests OAuth2 implementation through jdbc. * It's configured in a way that allows it to connect to SinglenodeOauth2 environment. In order for it to work, - * one must add to /etc/hosts following entries. They need to be removed before running Selenium tests against SinglenodeHydraSelenium environment. + * one must add to /etc/hosts following entries. They need to be removed before running automated tests against SinglenodeOAuth2* environments. * 127.0.0.1 presto-master * 127.0.0.1 hydra * 127.0.0.1 hydra-consent diff --git a/testing/trino-product-tests/pom.xml b/testing/trino-product-tests/pom.xml index a1edd7aaa2e0..4134d146e55c 100644 --- a/testing/trino-product-tests/pom.xml +++ b/testing/trino-product-tests/pom.xml @@ -111,6 +111,21 @@ guice + + com.squareup.okhttp3 + okhttp + + + + com.squareup.okhttp3 + okhttp-tls + + + + com.squareup.okhttp3 + okhttp-urlconnection + + io.confluent kafka-schema-registry-client @@ -141,32 +156,6 @@ annotations - - org.seleniumhq.selenium - selenium-api - - - - org.seleniumhq.selenium - selenium-chrome-driver - - - com.squareup.okio - okio - - - - - - org.seleniumhq.selenium - selenium-remote-driver - - - - org.seleniumhq.selenium - selenium-support - - org.testng testng diff --git a/testing/trino-product-tests/src/main/java/io/trino/tests/product/jdbc/TestExternalAuthorizerOAuth2.java b/testing/trino-product-tests/src/main/java/io/trino/tests/product/jdbc/TestExternalAuthorizerOAuth2.java index 7e6d4c8b5212..1eb9a80c4f40 100644 --- a/testing/trino-product-tests/src/main/java/io/trino/tests/product/jdbc/TestExternalAuthorizerOAuth2.java +++ b/testing/trino-product-tests/src/main/java/io/trino/tests/product/jdbc/TestExternalAuthorizerOAuth2.java @@ -13,181 +13,153 @@ */ package io.trino.tests.product.jdbc; +import com.google.common.collect.ImmutableList; import com.google.inject.Inject; import com.google.inject.name.Named; -import io.airlift.log.Logger; import io.trino.jdbc.TestingRedirectHandlerInjector; +import io.trino.tempto.BeforeTestWithContext; import io.trino.tempto.ProductTest; -import io.trino.testng.services.Flaky; import io.trino.tests.product.TpchTableResults; -import org.openqa.selenium.By; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.chrome.ChromeOptions; -import org.openqa.selenium.remote.RemoteWebDriver; -import org.openqa.selenium.support.ui.WebDriverWait; -import org.testng.annotations.AfterClass; +import okhttp3.JavaNetCookieJar; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.tls.HandshakeCertificates; import org.testng.annotations.Test; -import java.net.MalformedURLException; -import java.net.URL; +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.CookieManager; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.SQLException; import java.util.Properties; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import static com.google.common.util.concurrent.Futures.immediateFailedFuture; +import static com.google.common.base.Preconditions.checkState; +import static io.trino.tempto.assertions.QueryAssert.Row.row; import static io.trino.tempto.assertions.QueryAssert.assertThat; import static io.trino.tempto.query.QueryResult.forResultSet; import static io.trino.tests.product.TestGroups.OAUTH2; import static io.trino.tests.product.TestGroups.PROFILE_SPECIFIC_TESTS; -import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static java.util.Objects.requireNonNull; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.openqa.selenium.support.ui.ExpectedConditions.elementToBeClickable; public class TestExternalAuthorizerOAuth2 extends ProductTest { - private static final Logger log = Logger.get(TestExternalAuthorizerOAuth2.class); - @Inject @Named("databases.presto.jdbc_url") String jdbcUrl; - private final ExecutorService executor = newSingleThreadExecutor(); - private Future lastLoginAction; + @Inject + @Named("databases.presto.https_keystore_path") + String truststorePath; + + @Inject + @Named("databases.presto.https_keystore_password") + String truststorePassword; + + private OkHttpClient httpClient; - @AfterClass(alwaysRun = true) - public void clean() - throws InterruptedException + @BeforeTestWithContext + public void setUp() + throws Exception { - executor.shutdown(); - executor.awaitTermination(10, SECONDS); + OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); + KeyStore keyStore = KeyStore.getInstance(new File(truststorePath), truststorePassword.toCharArray()); + HandshakeCertificates.Builder certificatesBuilder = new HandshakeCertificates.Builder(); + keyStore.aliases().asIterator().forEachRemaining(alias -> { + try { + Certificate certificate = keyStore.getCertificate(alias); + if (certificate instanceof X509Certificate) { + certificatesBuilder.addTrustedCertificate((X509Certificate) certificate); + } + } + catch (KeyStoreException e) { + throw new RuntimeException(e); + } + }); + HandshakeCertificates certificates = certificatesBuilder.build(); + httpClientBuilder.sslSocketFactory(certificates.sslSocketFactory(), certificates.trustManager()); + httpClientBuilder.followRedirects(true); + httpClientBuilder.cookieJar(new JavaNetCookieJar(new CookieManager())); + httpClient = httpClientBuilder.build(); } @Test(groups = {OAUTH2, PROFILE_SPECIFIC_TESTS}) - @Flaky(issue = "https://github.com/trinodb/trino/issues/6991", match = "Last login action has failed with exception") public void shouldAuthenticateAndExecuteQuery() throws Exception { - prepareSeleniumHandler(); + prepareHandler(); Properties properties = new Properties(); properties.setProperty("user", "test"); try (Connection connection = DriverManager.getConnection(jdbcUrl, properties); PreparedStatement statement = connection.prepareStatement("SELECT * FROM tpch.tiny.nation"); ResultSet results = statement.executeQuery()) { - assertSuccessfulLogin(); assertThat(forResultSet(results)).matches(TpchTableResults.PRESTO_NATION_RESULT); } } @Test(groups = {OAUTH2, PROFILE_SPECIFIC_TESTS}) - @Flaky(issue = "https://github.com/trinodb/trino/issues/6991", match = "Last login action has failed with exception") public void shouldAuthenticateAfterTokenExpires() throws Exception { - prepareSeleniumHandler(); + prepareHandler(); Properties properties = new Properties(); properties.setProperty("user", "test"); try (Connection connection = DriverManager.getConnection(jdbcUrl, properties); PreparedStatement statement = connection.prepareStatement("SELECT * FROM tpch.tiny.nation"); ResultSet results = statement.executeQuery()) { - assertSuccessfulLogin(); + assertThat(forResultSet(results)).matches(TpchTableResults.PRESTO_NATION_RESULT); //Wait until the token expires. See: HydraIdentityProvider.TTL_ACCESS_TOKEN_IN_SECONDS SECONDS.sleep(10); try (PreparedStatement repeatedStatement = connection.prepareStatement("SELECT * FROM tpch.tiny.nation"); ResultSet repeatedResults = repeatedStatement.executeQuery()) { - assertSuccessfulLogin(); assertThat(forResultSet(repeatedResults)).matches(TpchTableResults.PRESTO_NATION_RESULT); } } } - private void prepareSeleniumHandler() - { - lastLoginAction = immediateFailedFuture(new AssertionError("Login action has not been triggered")); - TestingRedirectHandlerInjector.setRedirectHandler(uri -> { - lastLoginAction = executor.submit(() -> { - WebDriver driver = getWebDriver(); - driver.get(uri.toString()); - WebDriverWait wait = new WebDriverWait(driver, 10); - submitCredentials(driver, "foo@bar.com", "foobar", wait); - giveConsent(driver, wait); - }); - }); - } - - private WebDriver getWebDriver() - { - ChromeOptions options = new ChromeOptions(); - options.setAcceptInsecureCerts(true); - return new RemoteWebDriver(getWebDriverUrl(), options); - } - - private URL getWebDriverUrl() + @Test(groups = {OAUTH2, PROFILE_SPECIFIC_TESTS}) + public void shouldReturnGroups() + throws SQLException { - try { - return new URL("http", "selenium-chrome", 7777, "/wd/hub"); - } - catch (MalformedURLException e) { - throw new RuntimeException(e); + prepareHandler(); + Properties properties = new Properties(); + properties.setProperty("user", "test"); + try (Connection connection = DriverManager.getConnection(jdbcUrl, properties); + PreparedStatement statement = connection.prepareStatement("SELECT array_sort(current_groups())"); + ResultSet rs = statement.executeQuery()) { + assertThat(forResultSet(rs)).containsOnly(row(ImmutableList.of("admin", "public"))); } } - private void submitCredentials(WebDriver driver, String email, String password, WebDriverWait wait) + private void prepareHandler() { - log.info("trying to submit credentials"); - By emailElementLocator = By.id("email"); - log.info("waiting for email field"); - wait.until(elementToBeClickable(emailElementLocator)); - log.info("email field found"); - WebElement usernameElement = driver.findElement(emailElementLocator); - usernameElement.sendKeys(email); - log.info("email field set to %s", email); - log.info("waiting for password field"); - By passwordElementLocator = By.id("password"); - wait.until(elementToBeClickable(passwordElementLocator)); - log.info("password field found"); - WebElement passwordElement = driver.findElement(passwordElementLocator); - passwordElement.sendKeys(password + "\n"); - log.info("password field set to %s", password); - } - - private void giveConsent(WebDriver driver, WebDriverWait wait) - { - log.info("trying to give consent"); - log.info("waiting for openId checkbox"); - By openIdCheckboxLocator = By.id("openid"); - wait.until(elementToBeClickable(openIdCheckboxLocator)); - log.info("openId checkbox found"); - WebElement openIdCheckbox = driver.findElement(openIdCheckboxLocator); - openIdCheckbox.click(); - log.info("openId checkbox clicked"); - log.info("waiting for accept button"); - By acceptButtonLocator = By.id("accept"); - wait.until(elementToBeClickable(acceptButtonLocator)); - log.info("accept button found"); - WebElement acceptButton = driver.findElement(acceptButtonLocator); - acceptButton.click(); - log.info("accept button clicked"); - } - - private void assertSuccessfulLogin() - throws Exception - { - try { - lastLoginAction.get(); - } - catch (ExecutionException e) { - if (e.getCause() != null) { - throw new AssertionError("Last login action has failed with exception", e.getCause()); + TestingRedirectHandlerInjector.setRedirectHandler(uri -> { + try (Response response = httpClient.newCall( + new Request.Builder() + .get() + .url(uri.toString()) + .build()) + .execute()) { + int statusCode = response.code(); + checkState(statusCode == 200, "Invalid status %s", statusCode); + requireNonNull(response.body(), "body is null"); + String body = response.body().string(); + checkState(body.contains("OAuth2 authentication succeeded"), "Invalid response %s", body); } - throw e; - } + catch (IOException e) { + throw new UncheckedIOException(e); + } + }); } }