use of io.vertx.ext.auth.oauth2.OAuth2Options in project vertx-web by vert-x3.
the class WebExamples method example74.
public void example74(Vertx vertx, Router router) {
// create an OAuth2 provider, clientID and clientSecret
// should be requested to github
OAuth2Auth gitHubAuthProvider = GithubAuth.create(vertx, "CLIENT_ID", "CLIENT_SECRET");
// create a oauth2 handler on our running server
// the second argument is the full url to the callback
// as you entered in your provider management console.
OAuth2AuthHandler githubOAuth2 = OAuth2AuthHandler.create(vertx, gitHubAuthProvider, "https://myserver.com/github-callback");
// setup the callback handler for receiving the GitHub callback
githubOAuth2.setupCallback(router.route("/github-callback"));
// create an OAuth2 provider, clientID and clientSecret
// should be requested to Google
OAuth2Auth googleAuthProvider = OAuth2Auth.create(vertx, new OAuth2Options().setClientId("CLIENT_ID").setClientSecret("CLIENT_SECRET").setFlow(OAuth2FlowType.AUTH_CODE).setSite("https://accounts.google.com").setTokenPath("https://www.googleapis.com/oauth2/v3/token").setAuthorizationPath("/o/oauth2/auth"));
// create a oauth2 handler on our domain: "http://localhost:8080"
OAuth2AuthHandler googleOAuth2 = OAuth2AuthHandler.create(vertx, googleAuthProvider, "https://myserver.com/google-callback");
// setup the callback handler for receiving the Google callback
googleOAuth2.setupCallback(router.route("/google-callback"));
// At this point the 2 callbacks endpoints are registered:
// /github-callback -> handle github Oauth2 callbacks
// /google-callback -> handle google Oauth2 callbacks
// As the callbacks are made by the IdPs there's no header
// to identify the source, hence the need of custom URLs
// However for out Application we can control it so later
// we can add the right handler for the right tenant
router.route().handler(MultiTenantHandler.create("X-Tenant").addTenantHandler("github", githubOAuth2).addTenantHandler("google", googleOAuth2).addDefaultHandler(ctx -> ctx.fail(401)));
// Proceed using the router as usual.
}
use of io.vertx.ext.auth.oauth2.OAuth2Options in project vertx-web by vert-x3.
the class OAuth2AuthHandlerTest method testAuthPKCECodeFlow.
@Test
public void testAuthPKCECodeFlow() throws Exception {
final AtomicReference<String> verifier = new AtomicReference<>();
// lets mock a oauth2 server using code auth code flow
OAuth2Auth oauth2 = OAuth2Auth.create(vertx, new OAuth2Options().setClientId("client-id").setFlow(OAuth2FlowType.AUTH_CODE).setClientSecret("client-secret").setSite("http://localhost:10000"));
final CountDownLatch latch = new CountDownLatch(1);
HttpServer server = vertx.createHttpServer().requestHandler(req -> {
if (req.method() == HttpMethod.POST && "/oauth/token".equals(req.path())) {
req.setExpectMultipart(true).bodyHandler(buffer -> {
String[] parts = buffer.toString().split("&");
int matches = 0;
for (String part : parts) {
if (part.equals("code=1")) {
matches++;
}
if (part.startsWith("code_verifier=")) {
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
md.update(part.substring(14).getBytes(StandardCharsets.US_ASCII));
if (verifier.get().equals(Base64.getUrlEncoder().withoutPadding().encodeToString(md.digest()))) {
matches++;
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
if (part.equals("grant_type=authorization_code")) {
matches++;
}
}
assertEquals(3, matches);
req.response().putHeader("Content-Type", "application/json").end(fixture.encode());
});
} else if (req.method() == HttpMethod.POST && "/oauth/revoke".equals(req.path())) {
req.setExpectMultipart(true).bodyHandler(buffer -> req.response().end());
} else {
req.response().setStatusCode(400).end();
}
}).listen(10000, ready -> {
if (ready.failed()) {
throw new RuntimeException(ready.cause());
}
// ready
latch.countDown();
});
latch.await();
// ensure that there's a session
router.route().handler(SessionHandler.create(SessionStore.create(vertx)));
// create a oauth2 handler on our domain to the callback: "http://localhost:8080/callback"
OAuth2AuthHandler oauth2Handler = OAuth2AuthHandler.create(vertx, oauth2, "http://localhost:8080/callback").pkceVerifierLength(64);
// setup the callback handler for receiving the callback
oauth2Handler.setupCallback(router.route("/callback"));
// protect everything under /protected
router.route("/protected/*").handler(oauth2Handler);
// mount some handler under the protected zone
router.route("/protected/somepage").handler(rc -> {
assertNotNull(rc.user());
rc.response().end("Welcome to the protected resource!");
});
final AtomicReference<String> cookie = new AtomicReference<>();
final AtomicReference<String> state = new AtomicReference<>();
testRequest(HttpMethod.GET, "/protected/somepage", null, resp -> {
// in this case we should get a redirect
redirectURL = resp.getHeader("Location");
assertNotNull(redirectURL);
assertTrue(redirectURL.contains("&code_challenge="));
assertTrue(redirectURL.contains("&code_challenge_method="));
// save the params
String[] parts = redirectURL.substring(redirectURL.indexOf('?') + 1).split("&");
String codeChallenge = null;
String codeChallengeMethod = null;
String nonce = null;
for (String part : parts) {
if (part.startsWith("code_challenge=")) {
codeChallenge = part.substring(15);
}
if (part.startsWith("code_challenge_method=")) {
codeChallengeMethod = part.substring(22);
}
if (part.startsWith("state=")) {
nonce = part.substring(6);
}
}
assertNotNull(nonce);
assertNotNull(codeChallenge);
assertNotNull(codeChallengeMethod);
assertTrue(codeChallenge.length() >= 43 && codeChallenge.length() <= 128);
assertEquals("S256", codeChallengeMethod);
// save state
verifier.set(codeChallenge);
state.set(nonce);
cookie.set(resp.getHeader("set-cookie"));
}, 302, "Found", null);
// fake the redirect from IdP
testRequest(HttpMethod.GET, "/callback?state=" + state.get() + "&code=1", req -> {
// add the session cookie back to ensure the session gets updated
req.putHeader("cookie", cookie.get());
}, resp -> {
}, 302, "Found", "Redirecting to /protected/somepage.");
server.close();
}
use of io.vertx.ext.auth.oauth2.OAuth2Options in project vertx-web by vert-x3.
the class OAuth2AuthHandlerTest method testAuthCodeFlowBadSetup.
@Test
public void testAuthCodeFlowBadSetup() throws Exception {
// lets mock a oauth2 server using code auth code flow
OAuth2Auth oauth2 = OAuth2Auth.create(vertx, new OAuth2Options().setFlow(OAuth2FlowType.AUTH_CODE).setClientId("client-id").setClientSecret("client-secret").setSite("http://localhost:10000"));
final CountDownLatch latch = new CountDownLatch(1);
HttpServer server = vertx.createHttpServer().requestHandler(req -> {
if (req.method() == HttpMethod.POST && "/oauth/token".equals(req.path())) {
req.setExpectMultipart(true).bodyHandler(buffer -> req.response().putHeader("Content-Type", "application/json").end(fixture.encode()));
} else if (req.method() == HttpMethod.POST && "/oauth/revoke".equals(req.path())) {
req.setExpectMultipart(true).bodyHandler(buffer -> req.response().end());
} else {
req.response().setStatusCode(400).end();
}
}).listen(10000, ready -> {
if (ready.failed()) {
throw new RuntimeException(ready.cause());
}
// ready
latch.countDown();
});
latch.await();
// protect everything. This has the bad sideffect that it will also shade the callback route which is computed
// after this handler, the proper way to fix this would be create the route before
router.route().handler(OAuth2AuthHandler.create(vertx, oauth2, "http://localhost:8080/callback").setupCallback(router.route("/callback")));
// mount some handler under the protected zone
router.route("/protected/somepage").handler(rc -> {
assertNotNull(rc.user());
rc.response().end("Welcome to the protected resource!");
});
testRequest(HttpMethod.GET, "/protected/somepage", null, resp -> {
// in this case we should get a redirect
redirectURL = resp.getHeader("Location");
assertNotNull(redirectURL);
}, 302, "Found", null);
// fake the redirect
testRequest(HttpMethod.GET, "/callback?state=/protected/somepage&code=1", null, resp -> {
}, 500, "Internal Server Error", "Internal Server Error");
// second attempt with proper config
router.clear();
// protect everything.
OAuth2AuthHandler oauth2Handler = OAuth2AuthHandler.create(vertx, oauth2, "http://localhost:8080/callback").setupCallback(router.route("/callback"));
// now the callback is registered before as it should
router.route().handler(oauth2Handler);
// mount some handler under the protected zone
router.route("/protected/somepage").handler(rc -> {
assertNotNull(rc.user());
rc.response().end("Welcome to the protected resource!");
});
testRequest(HttpMethod.GET, "/protected/somepage", null, resp -> {
// in this case we should get a redirect
redirectURL = resp.getHeader("Location");
assertNotNull(redirectURL);
}, 302, "Found", null);
// fake the redirect
testRequest(HttpMethod.GET, "/callback?state=/protected/somepage&code=1", null, resp -> {
}, 200, "OK", "Welcome to the protected resource!");
server.close();
}
use of io.vertx.ext.auth.oauth2.OAuth2Options in project vertx-web by vert-x3.
the class OAuth2AuthHandlerTest method testAuthCodeFlowWithScopesInvalid.
@Test
public void testAuthCodeFlowWithScopesInvalid() throws Exception {
// lets mock an oauth2 server using code auth code flow
OAuth2Auth oauth2 = OAuth2Auth.create(vertx, new OAuth2Options().setClientId("client-id").setFlow(OAuth2FlowType.AUTH_CODE).setClientSecret("client-secret").setSite("http://localhost:10000"));
final CountDownLatch latch = new CountDownLatch(1);
HttpServer server = vertx.createHttpServer().requestHandler(req -> {
if (req.method() == HttpMethod.POST && "/oauth/token".equals(req.path())) {
req.setExpectMultipart(true).bodyHandler(buffer -> req.response().putHeader("Content-Type", "application/json").end(fixture.encode()));
} else if (req.method() == HttpMethod.POST && "/oauth/revoke".equals(req.path())) {
req.setExpectMultipart(true).bodyHandler(buffer -> req.response().end());
} else {
req.response().setStatusCode(400).end();
}
}).listen(10000, ready -> {
if (ready.failed()) {
throw new RuntimeException(ready.cause());
}
// ready
latch.countDown();
});
latch.await();
// create a oauth2 handler on our domain to the callback: "http://localhost:8080/callback"
OAuth2AuthHandler oauth2Handler = OAuth2AuthHandler.create(vertx, oauth2, "http://localhost:8080/callback").withScope("rea");
// setup the callback handler for receiving the callback
oauth2Handler.setupCallback(router.route("/callback"));
// protect everything under /protected
router.route("/protected/*").handler(oauth2Handler);
// mount some handler under the protected zone
router.route("/protected/somepage").handler(rc -> {
assertNotNull(rc.user());
rc.response().end("Welcome to the protected resource!");
});
testRequest(HttpMethod.GET, "/protected/somepage", null, resp -> {
// in this case we should get a redirect
redirectURL = resp.getHeader("Location");
assertNotNull(redirectURL);
}, 302, "Found", null);
// fake the redirect
testRequest(HttpMethod.GET, "/callback?state=/protected/somepage&code=1", 403, "Forbidden");
server.close();
}
use of io.vertx.ext.auth.oauth2.OAuth2Options in project vertx-web by vert-x3.
the class OAuth2AuthHandlerTest method testPasswordFlow.
@Test
public void testPasswordFlow() throws Exception {
// lets mock a oauth2 server using code auth code flow
OAuth2Auth oauth2 = OAuth2Auth.create(vertx, new OAuth2Options().setClientId("client-id").setClientSecret("client-secret").setSite("http://localhost:10000").setFlow(OAuth2FlowType.PASSWORD));
final CountDownLatch latch = new CountDownLatch(1);
HttpServer server = vertx.createHttpServer().requestHandler(req -> {
if (req.method() == HttpMethod.POST && "/oauth/token".equals(req.path())) {
req.setExpectMultipart(true).bodyHandler(buffer -> {
final String queryString = buffer.toString();
assertTrue(queryString.contains("username=paulo"));
assertTrue(queryString.contains("password=bananas"));
assertTrue(queryString.contains("grant_type=password"));
req.response().putHeader("Content-Type", "application/json").end(fixture.encode());
});
} else if (req.method() == HttpMethod.POST && "/oauth/revoke".equals(req.path())) {
req.setExpectMultipart(true).bodyHandler(buffer -> req.response().end());
} else {
req.response().setStatusCode(400).end();
}
}).listen(10000, ready -> {
if (ready.failed()) {
throw new RuntimeException(ready.cause());
}
// ready
latch.countDown();
});
latch.await();
AuthenticationHandler oauth2Handler = BasicAuthHandler.create(oauth2);
// protect everything under /protected
router.route("/protected/*").handler(oauth2Handler);
// mount some handler under the protected zone
router.route("/protected/somepage").handler(rc -> {
assertNotNull(rc.user());
rc.response().end("Welcome to the protected resource!");
});
testRequest(HttpMethod.GET, "/protected/somepage", req -> req.putHeader("Authorization", "Basic " + Base64.getEncoder().encodeToString("paulo:bananas".getBytes(StandardCharsets.UTF_8))), res -> {
// in this case we should get the resource
}, 200, "OK", "Welcome to the protected resource!");
testRequest(HttpMethod.GET, "/protected/somepage", 401, "Unauthorized");
server.close();
}
Aggregations