Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update example to demonstrate Java UID2 SDK - Basic Usage #10

Merged
merged 1 commit into from
Dec 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion publisher/uid2-java-test-site/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Java UID2 Integration Example

This example demonstrates how a content publisher can use the [UID2 services](https://github.com/UnifiedID2/uid2docs/tree/main) to implement the [custom UID2 integration workflow](https://github.com/UnifiedID2/uid2docs/blob/main/api/v2/guides/custom-publisher-integration.md).
This example demonstrates how a content publisher can use the [UID2 Java SDK](https://github.com/IABTechLab/uid2-client-java) to implement [UID2 Publisher integrations](https://github.com/UnifiedID2/uid2docs/blob/main/api/v2/guides/README.md).


>NOTE: While the server side of this example application is implemented in Java using Vert.x, it is not a requirement. You can use any technology of your choice and refer to the example application for illustration of the functionality that needs to be implemented.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ private void render(RoutingContext ctx, String templateFileName, JsonObject json
private static final String UID2_BASE_URL = System.getenv("UID2_BASE_URL");
private static final String UID2_API_KEY = System.getenv("UID2_API_KEY");
private static final String UID2_SECRET_KEY = System.getenv("UID2_SECRET_KEY");
private final PublisherUid2Helper publisherUid2Helper = new PublisherUid2Helper(UID2_SECRET_KEY);
private final PublisherUid2Helper publisherUid2Helper = new PublisherUid2Helper(UID2_SECRET_KEY); //for advanced usage (Do your own HTTP)
private final PublisherUid2Client publisherUid2Client = new PublisherUid2Client(UID2_BASE_URL, UID2_API_KEY, UID2_SECRET_KEY); //for basic usage (SDK does HTTP)


private int GetPort() {
Expand All @@ -61,13 +62,26 @@ private void renderError(HttpResponse<Buffer> response, String errorMessage, Rou

private WebClient webClient;

private void generateToken(RoutingContext ctx, String email, String redirect) {
private void generateTokenBasicUsage(RoutingContext ctx, String email) {
try {
IdentityTokens identity = publisherUid2Client.generateToken(TokenGenerateInput.fromEmail(email));

setIdentity(ctx, identity.getJsonString());
ctx.redirect("/basic/");
} catch (RuntimeException e) {
renderError(null, e.getMessage(), ctx);
}
}


private void generateTokenAdvancedUsage(RoutingContext ctx, String email, String redirect) {
try {
EnvelopeV2 envelope = publisherUid2Helper.createEnvelopeForTokenGenerateRequest(TokenGenerateInput.fromEmail(email));

webClient
.postAbs(UID2_BASE_URL + "/v2/token/generate")
.putHeader("Authorization", "Bearer " + UID2_API_KEY)
.putHeader("X-UID2-Client-Version", PublisherUid2Helper.getVersionHttpHeader())
.sendBuffer(Buffer.buffer(envelope.getEnvelope()))
.onSuccess(response -> {
if (response.statusCode() != 200) {
Expand Down Expand Up @@ -121,33 +135,50 @@ private void processRefreshIdentityResponse(HttpResponse<Buffer> encryptedRespon
}
}

private Future<Void> refreshIdentity(RoutingContext ctx) {
private Future<Void> refreshIdentity(RoutingContext ctx, boolean basicUsage) {
Promise<Void> promise = Promise.promise();

final IdentityTokens identity = getIdentity(ctx);
String refreshToken = identity.getRefreshToken();

webClient
.postAbs(UID2_BASE_URL + "/v2/token/refresh")
.putHeader("Authorization", "Bearer " + UID2_API_KEY)
.sendBuffer(Buffer.buffer(refreshToken))
.onSuccess(encryptedResponse -> {
processRefreshIdentityResponse(encryptedResponse, ctx, identity);
if (getIdentity(ctx) == null)

if (basicUsage) {
try {
TokenRefreshResponse tokenRefreshResponse = publisherUid2Client.refreshToken(identity);
String identityJsonString = tokenRefreshResponse.getIdentityJsonString();
setIdentity(ctx, identityJsonString);

if (identityJsonString == null)
promise.fail("no identity"); //eg opt out
else
promise.complete();
})
.onFailure(err -> {
renderError(null, err.getMessage(), ctx);
promise.fail("something went wrong" + err.getMessage());
});
} catch (RuntimeException e) {
renderError(null, e.getMessage(), ctx);
}
} else { //advanced usage
String refreshToken = identity.getRefreshToken();

webClient
.postAbs(UID2_BASE_URL + "/v2/token/refresh")
.putHeader("Authorization", "Bearer " + UID2_API_KEY)
.putHeader("X-UID2-Client-Version", PublisherUid2Helper.getVersionHttpHeader())
.sendBuffer(Buffer.buffer(refreshToken))
.onSuccess(encryptedResponse -> {
processRefreshIdentityResponse(encryptedResponse, ctx, identity);
if (getIdentity(ctx) == null)
promise.fail("no identity"); //eg opt out
else
promise.complete();
})
.onFailure(err -> {
renderError(null, err.getMessage(), ctx);
promise.fail("something went wrong" + err.getMessage());
});
}

return promise.future();
}


private Future<Void> verifyIdentity(RoutingContext ctx) {
private Future<Void> verifyIdentity(RoutingContext ctx, boolean basicUsage) {
Promise<Void> promise = Promise.promise();

IdentityTokens identity = getIdentity(ctx);
Expand All @@ -157,7 +188,7 @@ private Future<Void> verifyIdentity(RoutingContext ctx) {
}

if (identity.isDueForRefresh()) {
return refreshIdentity(ctx);
return refreshIdentity(ctx, basicUsage);
}

if (getIdentity(ctx) != null)
Expand All @@ -168,96 +199,145 @@ private Future<Void> verifyIdentity(RoutingContext ctx) {
return promise.future();
}

void protect(RoutingContext ctx) {
verifyIdentity(ctx)
void protect(RoutingContext ctx, boolean basicUsage) {
final String redirect = basicUsage ? "/basic/login" : "/login";

verifyIdentity(ctx, basicUsage)
.onSuccess(v -> ctx.next())
.onFailure(err -> {
setIdentity(ctx, null);
ctx.redirect("/login");
ctx.redirect(redirect);
});
}

private JsonObject getIdentityForTemplate(RoutingContext ctx) {
private JsonObject getIdentityForTemplate(RoutingContext ctx, String prefix) {
IdentityTokens identity = getIdentity(ctx);
return new JsonObject().put("identity", new JsonObject(identity.getJsonString()).encodePrettily());
return new JsonObject().put("prefix", prefix).put("identity", new JsonObject(identity.getJsonString()).encodePrettily());
}

private TemplateEngine engine;

private Router createRoutesSetupForServerOnlyIntegration() {
engine = FreeMarkerTemplateEngine.create(vertx);
private Router createRoutesSetupForAdvancedUsageServerOnly() {
final Router router = Router.router(vertx);

router.route().handler(BodyHandler.create());
router.route().handler(SessionHandler.create(CookieSessionStore.create(vertx, "my-secret")));
router.route().handler(StaticHandler.create("webroot"));

router.get("/login").handler(ctx ->
verifyIdentity(ctx)
verifyIdentity(ctx, false)
.onSuccess(v -> ctx.redirect("/"))
.onFailure(v -> {
setIdentity(ctx, null);
render(ctx, "templates/login.ftl", new JsonObject());
render(ctx, "templates/login.ftl", new JsonObject().put("redirect", "/login"));
})
);

router.post("/login").handler(ctx ->
generateToken(ctx, ctx.request().getFormAttribute("email"), "/")
generateTokenAdvancedUsage(ctx, ctx.request().getFormAttribute("email"), "/")
);

router.get("/logout").handler(ctx -> {
setIdentity(ctx, null);
ctx.redirect("/login");
});

router.get("/").handler(this::protect);
router.get("/content1").handler(this::protect);
router.get("/content2").handler(this::protect);
router.get("/").handler(ctx -> protect(ctx, false));
router.get("/content1").handler(ctx -> protect(ctx, false));
router.get("/content2").handler(ctx -> protect(ctx, false));

router.get("/").handler(ctx -> {
JsonObject jsonObject = getIdentityForTemplate(ctx);
JsonObject jsonObject = getIdentityForTemplate(ctx, "");
render(ctx, "templates/index.ftl", jsonObject);
});

router.get("/content1").handler(ctx -> {
JsonObject jsonObject = getIdentityForTemplate(ctx).put("content", "First Sample Content");
JsonObject jsonObject = getIdentityForTemplate(ctx, "").put("content", "First Sample Content");
render(ctx, "templates/content.ftl", jsonObject);
});

router.get("/content2").handler(ctx -> {
JsonObject jsonObject = getIdentityForTemplate(ctx).put("content", "Second Sample Content");
JsonObject jsonObject = getIdentityForTemplate(ctx, "").put("content", "Second Sample Content");
render(ctx, "templates/content.ftl", jsonObject);
});

return router;
}

private Router createRoutesSetupForStandardIntegration() {
private Router createRoutesSetupForAdvancedUsageStandardIntegration() {
Router standardIntegration = Router.router(vertx);

standardIntegration.get("/").handler(ctx ->
render(ctx, "templates-standard-integration/index.ftl", new JsonObject().put("uid2BaseUrl", UID2_BASE_URL)));

standardIntegration.post("/login").handler(ctx ->
generateToken(ctx, ctx.request().getFormAttribute("email"), "/standard/login"));
generateTokenAdvancedUsage(ctx, ctx.request().getFormAttribute("email"), "/standard/login"));

standardIntegration.get("/login").handler(ctx ->
render(ctx, "templates-standard-integration/login.ftl", getIdentityForTemplate(ctx).put("uid2BaseUrl", UID2_BASE_URL)));
render(ctx, "templates-standard-integration/login.ftl", getIdentityForTemplate(ctx, "/standard").put("uid2BaseUrl", UID2_BASE_URL)));

return standardIntegration;
}

private Router createRouteSetupForBasicUsageServerOnly() {
final Router router = Router.router(vertx);

router.route().handler(BodyHandler.create());
router.route().handler(SessionHandler.create(CookieSessionStore.create(vertx, "my-secret")));
router.route().handler(StaticHandler.create("webroot"));

router.get("/login").handler(ctx ->
verifyIdentity(ctx, true)
.onSuccess(v -> ctx.redirect("/"))
.onFailure(v -> {
setIdentity(ctx, null);
render(ctx, "templates/login.ftl", new JsonObject().put("redirect", "/basic/login"));
})
);

router.post("/login").handler(ctx -> generateTokenBasicUsage(ctx, ctx.request().getFormAttribute("email")));

router.get("/logout").handler(ctx -> {
setIdentity(ctx, null);
ctx.redirect("/basic/login");
});

router.get("/").handler(ctx -> protect(ctx, true));
router.get("/content1").handler(ctx -> protect(ctx, true));
router.get("/content2").handler(ctx -> protect(ctx, true));

router.get("/").handler(ctx -> {
JsonObject jsonObject = getIdentityForTemplate(ctx, "/basic");
render(ctx, "templates/index.ftl", jsonObject);
});

router.get("/content1").handler(ctx -> {
JsonObject jsonObject = getIdentityForTemplate(ctx, "/basic").put("content", "First Sample Content");
render(ctx, "templates/content.ftl", jsonObject);
});

router.get("/content2").handler(ctx -> {
JsonObject jsonObject = getIdentityForTemplate(ctx, "/basic").put("content", "Second Sample Content");
render(ctx, "templates/content.ftl", jsonObject);
});

return router;

}

@Override
public void start(Promise<Void> startPromise) {
webClient = WebClient.create(vertx);
engine = FreeMarkerTemplateEngine.create(vertx);

Router serverOnlyRouter = createRoutesSetupForServerOnlyIntegration();
Router standardIntegrationRouter = createRoutesSetupForStandardIntegration();
Router serverOnlyRouter = createRoutesSetupForAdvancedUsageServerOnly();
Router standardIntegrationRouter = createRoutesSetupForAdvancedUsageStandardIntegration();
Router serverOnlyWithBasicUsage = createRouteSetupForBasicUsageServerOnly();

Router parentRouter = Router.router(vertx);
parentRouter.route("/*").subRouter(serverOnlyRouter);
parentRouter.route("/standard/*").subRouter(standardIntegrationRouter);

parentRouter.route("/basic/*").subRouter(serverOnlyWithBasicUsage);

vertx.createHttpServer().requestHandler(parentRouter).listen(GetPort())
.onSuccess(server -> System.out.println("HTTP server started on http://localhost:" + server.actualPort()))
Expand Down
2 changes: 1 addition & 1 deletion publisher/uid2-java-test-site/templates/content.ftl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<#include "header.html">
<p>Protected Content &mdash; accessible only with a valid UID2 identity:</p>
<pre>${content}</pre>
<p><a href="/">Back to the main page</a></p>
<p><a href="${prefix}/">Back to the main page</a></p>
<#include "identity.ftl">
<#include "footer.html">
2 changes: 1 addition & 1 deletion publisher/uid2-java-test-site/templates/error.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
<pre>${response}</pre>
<p>HTTP error:</p>
<pre>${responseStatus}</pre>
<p><a href="/">Back to the main page</a></p>
<p><a href="${prefix}/">Back to the main page</a></p>
<#include "footer.html">
2 changes: 1 addition & 1 deletion publisher/uid2-java-test-site/templates/identity.ftl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<pre>${identity}</pre>
<div id="logout_form" class="form"><form action="/logout" method="GET">
<div id="logout_form" class="form"><form action="${prefix}/logout" method="GET">
<input type="submit" value="Log Out" class="button">
</form></div>
4 changes: 2 additions & 2 deletions publisher/uid2-java-test-site/templates/index.ftl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<#include "header.html">
<p>Protected Content &mdash; accessible only with a valid UID2 identity:</p>
<ul>
<li><a href="/content1">Sample Page 1</a></li>
<li><a href="/content2">Sample Page 2</a></li>
<li><a href="${prefix}/content1">Sample Page 1</a></li>
<li><a href="${prefix}/content2">Sample Page 2</a></li>
</ul>
<p>Current UID2 Identity:</p>
<#include "identity.ftl">
Expand Down
2 changes: 1 addition & 1 deletion publisher/uid2-java-test-site/templates/login.ftl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<#include "header.html">
<div id="login_form" class="form"><form action="/login" method="POST">
<div id="login_form" class="form"><form action="${redirect}" method="POST">
<div class="email_prompt"><input type="text" id="email" name="email" placeholder="Enter an email address" style="border-style: none;"></div>
<div><input type="submit" value="Log In" class="button"></div>
</form></div>
Expand Down