This commit is contained in:
Ryan Esch 2018-04-20 13:16:52 -05:00
parent 32974d8ff5
commit 180c6f000f
27 changed files with 517 additions and 286 deletions

View File

@ -10,16 +10,13 @@ liberty {
dropins = [war]
bootstrapProperties = ['httpPort': httpPort, 'httpsPort': httpsPort]
configDirectory = file('src/main/liberty/config')
features {
name = ['sociallogin-1.0']
acceptLicense = true
}
}
}
dependencies {
providedCompile group: 'com.ibm.websphere.appserver.api', name: 'com.ibm.websphere.appserver.api.security', version: '1.2.19'
providedCompile group: 'com.ibm.websphere.appserver.api', name: 'com.ibm.websphere.appserver.api.jwt', version: '1.1.19'
providedCompile group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.0'
providedCompile group: 'com.ibm.websphere.appserver.api', name: 'com.ibm.websphere.appserver.api.security', version: '1.2.+'
providedCompile group: 'com.ibm.websphere.appserver.api', name: 'com.ibm.websphere.appserver.api.jwt', version: '1.1.+'
compile group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.0'
compile group: 'com.google.api-client', name: 'google-api-client', version: '1.23.0'
}

View File

@ -0,0 +1,11 @@
package org.libertybikes.auth.service;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class AuthApp extends Application {
public static final String HTTPS_AUTH_SERVICE = "https://localhost:8482/auth-service";
public static final String FRONTEND_URL = "http://localhost:12000/login";
}

View File

@ -0,0 +1,23 @@
/**
*
*/
package org.libertybikes.auth.service;
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
@Provider
public class CORSFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
responseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
responseContext.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
responseContext.getHeaders().add("Access-Control-Allow-Credentials", "true");
responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
responseContext.getHeaders().add("Access-Control-Max-Age", "1209600");
}
}

View File

@ -0,0 +1,71 @@
/**
*
*/
package org.libertybikes.auth.service;
import java.net.URI;
import java.util.Arrays;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
@Path("/GoogleAuth")
@ApplicationScoped
public class GoogleAuth {
private static final long serialVersionUID = 1L;
@Inject
@ConfigProperty(name = "googleOAuthConsumerKey")
String key;
@Inject
@ConfigProperty(name = "googleOAuthConsumerSecret")
String secret;
@Inject
@ConfigProperty(name = "auth_url", defaultValue = "https://localhost:8482/auth-service")
String authUrl;
@Context
HttpServletRequest request;
@GET
public Response getAuthURL() {
JsonFactory jsonFactory = new JacksonFactory();
HttpTransport httpTransport = new NetHttpTransport();
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow(httpTransport, jsonFactory, key, secret, Arrays
.asList("https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email"));
try {
// google will tell the users browser to go to this address once
// they are done authing.
String callbackURL = authUrl + "/GoogleCallback";
request.getSession().setAttribute("google", flow);
String authorizationUrl = flow.newAuthorizationUrl().setRedirectUri(callbackURL).build();
// send the user to google to be authenticated.
return Response.temporaryRedirect(new URI(authorizationUrl)).build();
} catch (Exception e) {
e.printStackTrace();
return Response.status(500).build();
}
}
}

View File

@ -0,0 +1,129 @@
package org.libertybikes.auth.service;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.javanet.NetHttpTransport;
/**
* Servlet implementation class googleCallback
*/
@Path("/GoogleCallback")
@ApplicationScoped
public class GoogleCallback extends JwtAuth {
private static final long serialVersionUID = 1L;
@Context
HttpServletRequest request;
@Inject
@ConfigProperty(name = "frontend_url", defaultValue = AuthApp.FRONTEND_URL)
String frontendUrl;
@Inject
@ConfigProperty(name = "auth_url", defaultValue = AuthApp.HTTPS_AUTH_SERVICE)
String authUrl;
private GoogleAuthorizationCodeFlow flow = null;
/**
* Method that performs introspection on an AUTH string, and returns data as
* a String->String hashmap.
*
* @param auth
* the authstring to query, as built by an auth impl.
* @return the data from the introspect, in a map.
* @throws IOException
* if anything goes wrong.
*/
public Map<String, String> introspectAuth(GoogleTokenResponse gResponse) throws IOException {
Map<String, String> results = new HashMap<String, String>();
Credential credential = flow.createAndStoreCredential(gResponse, null);
System.out.println(credential.toString());
try {
// ask google to verify the response from the auth string
// if invalid, it'll throw an exception
HttpRequestFactory requestFactory = new NetHttpTransport().createRequestFactory(credential);
GenericUrl url = new GenericUrl("https://www.googleapis.com/oauth2/v3/userinfo");
HttpRequest infoRequest = requestFactory.buildGetRequest(url);
infoRequest.getHeaders().setContentType("application/json");
String jsonIdentity = infoRequest.execute().parseAsString();
ObjectMapper objectMapper = new ObjectMapper();
JsonNode user = objectMapper.readTree(jsonIdentity);
String name = user.get("name").asText();
String email = user.get("email").asText();
results.put("valid", "true");
results.put("id", "GOOGLE:" + email);
results.put("upn", email);
results.put("name", name);
results.put("email", email);
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
results.put("valid", "false");
}
return results;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getAuthURL() throws IOException, URISyntaxException {
// google calls us back at this app when a user has finished authing with them.
// when it calls us back here, it passes an oauth_verifier token that we
// can exchange for a google access token.
flow = (GoogleAuthorizationCodeFlow) request.getSession().getAttribute("google");
String code = request.getParameter("code");
//now we need to invoke the access_token endpoint to swap the code for a token.
String callbackURL = authUrl + "/GoogleCallback";
GoogleTokenResponse gResponse;
Map<String, String> claims = new HashMap<String, String>();
try {
gResponse = flow.newTokenRequest(code).setRedirectUri(callbackURL.toString()).execute();
claims = introspectAuth(gResponse);
} catch (IOException e) {
e.printStackTrace();
}
// if auth key was no longer valid, we won't build a JWT. Redirect back to start.
if (!"true".equals(claims.get("valid"))) {
return Response.temporaryRedirect(new URI(frontendUrl)).build();
} else {
String newJwt = createJwt(claims);
return Response.temporaryRedirect(new URI(frontendUrl + "/" + newJwt)).build();
}
}
}

View File

@ -0,0 +1,127 @@
package org.libertybikes.auth.service;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Calendar;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
/**
* A base class for bikes auth implementations that return signed JWTs to the
* client.
*/
public abstract class JwtAuth {
private static final long serialVersionUID = 1L;
@Resource(lookup = "jwtKeyStore")
protected String keyStore;
@Inject
@ConfigProperty(name = "jwtKeyStorePassword", defaultValue = "secret")
String keyStorePW;
@Inject
@ConfigProperty(name = "jwtKeyStoreAlias", defaultValue = "bike")
String keyStoreAlias;
protected static Key signingKey = null;
/**
* Obtain the key we'll use to sign the jwts we issue.
*
* @throws IOException
* if there are any issues with the keystore processing.
*/
private synchronized void getKeyStoreInfo() throws IOException {
try {
// load up the keystore
FileInputStream is = new FileInputStream(keyStore);
KeyStore signingKeystore = KeyStore.getInstance(KeyStore.getDefaultType());
signingKeystore.load(is, keyStorePW.toCharArray());
try {
signingKey = signingKeystore.getKey(keyStoreAlias, keyStorePW.toCharArray());
} catch (UnrecoverableKeyException e) {
System.out.println("exception: " + e);
e.printStackTrace();
}
} catch (KeyStoreException e) {
throw new IOException(e);
} catch (NoSuchAlgorithmException e) {
throw new IOException(e);
} catch (CertificateException e) {
throw new IOException(e);
}
}
/**
* Obtain a JWT with the claims supplied. The key "id" will be used to set
* the JWT subject.
*
* @param claims map of string->string for claim data to embed in the jwt.
* @return jwt encoded as string, ready to send to http.
* @throws IOException if there are keystore issues.
*/
protected String createJwt(Map<String, String> claims) throws IOException {
if (signingKey == null) {
getKeyStoreInfo();
}
Claims onwardsClaims = Jwts.claims();
// Add all the remaining claims as-is.
onwardsClaims.putAll(claims);
// Set the subject using the "id" field from our claims map.
onwardsClaims.setSubject(claims.get("id"));
onwardsClaims.setId(claims.get("id"));
// We'll use this claim to know this is a user token
onwardsClaims.setAudience("client");
onwardsClaims.setIssuer("https://accounts.google.com");
// we set creation time to 24hrs ago, to avoid timezone issues in the
// browser verification of the jwt.
Calendar calendar1 = Calendar.getInstance();
calendar1.add(Calendar.HOUR, -24);
onwardsClaims.setIssuedAt(calendar1.getTime());
// client JWT has 24 hrs validity from now.
Calendar calendar2 = Calendar.getInstance();
calendar2.add(Calendar.HOUR, 24);
onwardsClaims.setExpiration(calendar2.getTime());
// finally build the new jwt, using the claims we just built, signing it
// with our signing key, and adding a key hint as kid to the encryption header,
// which is optional, but can be used by the receivers of the jwt to know which
// key they should verify it with.
String newJwt = null;
newJwt = Jwts.builder()
.setHeaderParam("kid", "bike")
.setHeaderParam("alg", "RS256")
.setClaims(onwardsClaims)
.signWith(SignatureAlgorithm.RS256, signingKey)
.compact();
return newJwt;
}
}

View File

@ -1,9 +0,0 @@
package org.libertybikes.player.service;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class AuthApp extends Application {
}

View File

@ -1,112 +0,0 @@
package org.libertybikes.player.service;
import java.security.Principal;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import org.eclipse.microprofile.jwt.JsonWebToken;
//import com.ibm.websphere.security.jwt.JwtBuilder;
//import com.ibm.websphere.security.jwt.JwtToken;
//import com.ibm.websphere.security.WSSecurityException;
//import com.ibm.websphere.security.auth.CredentialDestroyedException;
//import com.ibm.websphere.security.auth.WSSubject;
//import com.ibm.websphere.security.cred.WSCredential;
//import com.ibm.websphere.security.jwt.JwtBuilder;
//import com.ibm.websphere.security.jwt.JwtToken;
@Path("/")
@ApplicationScoped
public class AuthAttr {
private Object exptime;
@Inject
private Principal principal;
@Context
HttpServletRequest request;
@Inject
private JsonWebToken callerPrincipal;
@GET
@Path("/ryan")
@Produces(MediaType.APPLICATION_JSON)
public String getToken(/** @Context SecurityContext sec */
) {
Cookie[] cookie = request.getCookies();
String jwt = (String) request.getSession().getAttribute("jwt");
// System.out.println("cookie: " + cookie.length);
System.out.println("~header " + request.getHeader("Authorization"));
return callerPrincipal.getName();
//return jwt;
//UserProfileManager.getUserProfile().getAccessToken()
// String claimString = "";
// Set<String> claims = callerPrincipal.getClaimNames();
// for (String claim : claims) {
// claimString += claim + ": " + callerPrincipal.getClaim(claim) + "\n";
// }
// return claimString;
// return principal.getName();
// GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow(new NetHttpTransport(), new JacksonFactory(), "key", "secret", Arrays
// .asList("https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email"));
//
// Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
// Put the user info into a JWT Token
// create() uses default settings.
// For other settings, specify a JWTBuilder element in server.xml
// and call create(builder id)
// String user = principal.getName();
// long exptime = 0;
// String jwtTokenString = null;
// try {
// JwtBuilder builder = com.ibm.websphere.security.jwt.JwtBuilder.create("jwtUserBuilder");
// builder.subject(user);
// builder.claim("upn", user);
//// builder.claim("groups", groups);
// builder.claim("iss", "https://localhost:8482/auth-service/token");//request.getRequestURL().toString());
//
// JwtToken theToken = builder.buildJwt();
// exptime = theToken.getClaims().getExpiration();
// jwtTokenString = theToken.compact();
// } catch (Exception e) {
// System.out.println(e);
// }
// // populate the bean for easy conversion to json
// Token tb = new Token();
// tb.setToken(jwtTokenString);
// tb.setExpires(Long.toString(exptime));
// return Response.ok(tb).build();
// return user;
// URI uri = null;
// try {
// uri = new URI("public");
// } catch (URISyntaxException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// return Response.temporaryRedirect(uri).build();
}
@GET
@Path("/public")
public String publicResource() {
return "This is a public resource";
}
}

View File

@ -1,64 +0,0 @@
package org.libertybikes.player.service;
import java.io.IOException;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ibm.websphere.security.jwt.JwtBuilder;
import com.ibm.websphere.security.jwt.JwtToken;
//import com.ibm.websphere.security.jwt.JwtBuilder;
//import com.ibm.websphere.security.jwt.JwtToken;
//import com.ibm.websphere.security.WSSecurityException;
//import com.ibm.websphere.security.auth.CredentialDestroyedException;
//import com.ibm.websphere.security.auth.WSSubject;
//import com.ibm.websphere.security.cred.WSCredential;
//import com.ibm.websphere.security.jwt.JwtBuilder;
//import com.ibm.websphere.security.jwt.JwtToken;
@WebServlet("/token")
public class AuthService extends HttpServlet {
private static final long serialVersionUID = 2202953742584558018L;
// @Inject
// private JsonWebToken callerPrincipal;
private static final Jsonb jsonb = JsonbBuilder.create();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String user = req.getUserPrincipal().getName();
long exptime = 0;
String jwtTokenString = null;
try {
JwtBuilder builder = JwtBuilder.create("jwtUserBuilder");
builder.subject(user);
builder.claim("upn", user);
// builder.claim("groups", groups);
builder.claim("iss", "https://localhost:8482/auth-service/token");//request.getRequestURL().toString());
JwtToken theToken = builder.buildJwt();
exptime = theToken.getClaims().getExpiration();
jwtTokenString = theToken.compact();
} catch (Exception e) {
System.out.println(e);
}
// populate the bean for easy conversion to json
Token tb = new Token();
tb.token = jwtTokenString;
tb.expires = Long.toString(exptime);
req.getSession().setAttribute("jwt", jwtTokenString);
resp.getWriter().println(jsonb.toJson(tb));
resp.setHeader("Authorization", "Bearer " + jwtTokenString);
resp.sendRedirect("ryan");
}
}

View File

@ -1,22 +0,0 @@
package org.libertybikes.player.service;
public class Token {
String token;
String expires;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getExpires() {
return expires;
}
public void setExpires(String expires) {
this.expires = expires;
}
}

View File

@ -2,9 +2,6 @@
<featureManager>
<feature>microProfile-1.2</feature>
<feature>appSecurity-2.0</feature>
<feature>socialLogin-1.0</feature>
<feature>servlet-4.0</feature>
<feature>jsonb-1.0</feature>
</featureManager>
<httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="${httpPort}" httpsPort="${httpsPort}" />
@ -18,36 +15,14 @@
trustStoreRef="validationKeystore" />
<keyStore
id="validationKeystore"
password="Passw0rd"
password="secret"
type="jks"
location="${server.config.dir}resources/security/validationKeystore.jks" />
<keyStore id="defaultKeyStore" password="Liberty" />
<keyStore id="defaultKeyStore" password="Liberty" />
<quickStartSecurity userName="admin" userPassword="admin"/>
<googleLogin clientId="555751036911-3jhglsli8kr30h3d7qmuuldlqrk7r4f6.apps.googleusercontent.com" clientSecret="QkbOSVJCUSu436quyDHmSzbr" />
<variable name="jwt.issuer" value="https://localhost:8482/auth-service/token"/>
<!-- This JWT builder is used to build a JWT for an authenticated user. -->
<jwtBuilder id="jwtUserBuilder" issuer="${jwt.issuer}" expiry="24h" keyAlias="default" jti="true" audiences="bigmatch"/>
<!--
<mpJwt
id="myMpJwt"
jwksUri="https://www.googleapis.com/oauth2/v3/certs"
issuer="https://accounts.google.com"
audiences="555751036911-3jhglsli8kr30h3d7qmuuldlqrk7r4f6.apps.googleusercontent.com">
</mpJwt>
-->
<!--
<application type="war" id="test" name="test" location="${server.config.dir}/dropins/auth-service.war.xml">
<application-bnd>
<security-role name="blarg">
<special-subject type="ALL_AUTHENTICATED_USERS" />
</security-role>
</application-bnd>
</application>
-->
<jndiEntry jndiName="jwtKeyStore" value="${server.config.dir}resources/security/validationKeystore.jks"/>
<logging traceSpecification="*=info:com.ibm.ws.security.*=all:com.ibm.websphere.security.wim.*=all:Authentication=all:com.ibm.ws.container.service.security.internal.*=all" />
</server>

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>test</display-name>
<!-- SECURITY -->
<security-role>
<role-name>user</role-name>
</security-role>
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Programmatic Api Servlet (by Form Login)</web-resource-name>
<url-pattern>/token</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>**</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
</web-app>

View File

@ -9,6 +9,7 @@ import { environment } from './../environments/environment';
const routes: Routes = [
{ path: 'login', component: LoginComponent },
{ path: 'login/:jwt', component: LoginComponent },
{ path: 'game', component: GameComponent },
{ path: 'play', component: ControlsComponent },
{ path: '', redirectTo: '/login', pathMatch: 'full'}

View File

@ -13,7 +13,10 @@
<div leftPane>
<div class="form-group">
<div class="form-item">
<button type="button" (click)="showGuestLogin()">Play</button>
<button type="button" (click)="showGuestLogin()">Play as Guest</button>
</div>
<div class="form-item">
<button type="button" (click)="loginGoogle()">Sign in with Google</button>
</div>
<h2 class="section-header">or</h2>
<div class="form-item">
@ -30,7 +33,7 @@
<input type="text" id="username" name="username" [(ngModel)]="username" />
</div>
<div class="form-item">
<button type="button" (click)="loginAsGuest(username)">Sign In</button>
<button type="button" (click)="loginAsGuest(username)">Sign In As Guest</button>
</div>
<div class="form-item">
<button type="button" (click)="cancelLogin()">Cancel</button>

View File

@ -1,7 +1,7 @@
import { Component, OnInit, NgZone, HostBinding } from '@angular/core';
import { Meta } from '@angular/platform-browser';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { Router, ActivatedRoute } from '@angular/router';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { trigger, animate, style, transition, group, query, stagger, state } from '@angular/animations';
import { environment } from './../../environments/environment';
import { PaneType } from '../slider/slider.component';
@ -22,26 +22,40 @@ export class LoginComponent implements OnInit {
private router: Router,
private ngZone: NgZone,
private meta: Meta,
private http: HttpClient
private http: HttpClient,
private route: ActivatedRoute
) {}
ngOnInit() {
this.meta.removeTag('viewport');
let viewWidth = window.innerWidth;
let viewHeight = window.innerHeight;
this.meta.addTag({name: 'viewport', content: `width=${viewWidth}, height=${viewHeight}, initial-scale=1.0`}, true);
this.route.params.subscribe( params =>
{
localStorage.setItem("jwt", params['jwt']);
});
if (localStorage.getItem('jwt') !== null && localStorage.getItem('jwt') !== 'undefined') {
this.loginThroughGoogle();
}
if (sessionStorage.getItem('username') !== null) {
this.username = sessionStorage.getItem('username');
this.player.name = this.username;
}
}
loginGoogle() {
window.location.href = `http://${environment.API_URL_AUTH}/auth-service/GoogleAuth`;
}
async quickJoin() {
// First get an unstarted round ID
let roundID = await this.http.get(`${environment.API_URL_GAME_ROUND}/available`, { responseType: 'text' }).toPromise();
// Then join the round
this.joinRoundById(roundID);
}
@ -89,16 +103,20 @@ export class LoginComponent implements OnInit {
return;
}
let response: any = await this.http.post(`${environment.API_URL_PLAYERS}/create?name=${this.username}`, '', {
let id = sessionStorage.getItem('userId');
let response: any = await this.http.post(`${environment.API_URL_PLAYERS}/create?name=${this.username}&id=${id}`, '', {
responseType: 'text'
}).toPromise();
}).toPromise();
console.log(JSON.stringify(response));
console.log(`Created a new player with ID=${response}`);
sessionStorage.setItem('userId', response);
// TEMP: to prevent a race condition, putting this code inside of the player create callback to ensure that
// userId is set in the session storage before proceeding to the game board
sessionStorage.setItem('username', this.username);
if (id === null) {
sessionStorage.setItem('userId', response);
sessionStorage.setItem('username', this.username);
}
sessionStorage.setItem('isSpectator', 'false');
sessionStorage.setItem('roundId', roundID);
if (gameBoard === true) {
@ -121,9 +139,10 @@ export class LoginComponent implements OnInit {
// this post request takes a noticeable amount of time
let ngZone = this.ngZone;
let router = this.router;
try {
let party: any = await this.http.post(`${environment.API_URL_PARTY}/create`, '', { responseType: 'json' }).toPromise();
let party: any = await this.http.post(`${environment.API_URL_PARTY}/create`, '', { responseType: 'json' }).toPromise();
console.log(`Created round with id=${party}`);
sessionStorage.setItem('isSpectator', 'true');
sessionStorage.setItem('partyId', party.id);
sessionStorage.setItem('roundId', party.currentRound.id);
@ -146,13 +165,38 @@ export class LoginComponent implements OnInit {
return;
}
this.player.name = username;
this.username = username;
sessionStorage.setItem('username', username);
this.pane = 'right';
}
async loginThroughGoogle() {
let jwt = localStorage.getItem("jwt");
let user: any = await this.http.get(`${environment.API_URL_PLAYERS}/getJWTInfo`, { responseType: 'json', headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + `${jwt}`
}) }).toPromise();
if (user.exists === 'true') {
sessionStorage.setItem('username', user.username);
sessionStorage.setItem('userId', user.id);
this.player.name = user.username;
} else {
var username = prompt("Choose a username:", "");
this.player.name = username;
sessionStorage.setItem('username', username);
sessionStorage.setItem('userId', user.id);
//register a new user
let response: any = await this.http.post(`${environment.API_URL_PLAYERS}/create?name=${username}&id=${user.id}`, '', {
responseType: 'text'
}).toPromise();
}
this.pane = 'right';
}
logout() {
this.pane = 'left';
sessionStorage.removeItem('username');
sessionStorage.removeItem('userId');
}
cancelLogin() {

View File

@ -12,6 +12,7 @@ liberty {
name = 'game-service'
dropins = [war]
bootstrapProperties = ['httpPort': httpPort, 'httpsPort': httpsPort]
configDirectory = file('src/main/liberty/config')
jvmOptions = ['-Dorg.libertybikes.restclient.PlayerService/mp-rest/url=http://localhost:8081/']
}
}

View File

@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.enterprise.concurrent.ManagedScheduledExecutorService;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
@ -17,6 +18,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.libertybikes.game.core.GameRound;
import org.libertybikes.game.core.GameRound.State;
@ -24,6 +26,9 @@ import org.libertybikes.game.core.GameRound.State;
@ApplicationScoped
public class GameRoundService {
@Inject
private JsonWebToken callerPrincipal;
@Resource
ManagedScheduledExecutorService exec;

View File

@ -11,8 +11,18 @@
<httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="${httpPort}" httpsPort="${httpsPort}" />
<applicationManager autoExpand="true"/>
<keyStore id="defaultKeyStore" password="Liberty"/>
<sslDefault sslRef="RpSSLConfig" />
<ssl
id="RpSSLConfig"
keyStoreRef="validationKeystore"
trustStoreRef="validationKeystore" />
<keyStore
id="validationKeystore"
password="secret2"
type="jks"
location="${server.config.dir}resources/security/validationKeystore.jks" />
<keyStore id="defaultKeyStore" password="secret2" />
<quickStartSecurity userName="admin" userPassword="admin"/>
<!-- This configuration allows cross-origin HTTP requests, such
@ -22,4 +32,6 @@
allowedMethods="GET, DELETE, POST, PUT"
allowedHeaders="Accept, Content-Type, Authorization"
maxAge="3600" />
<logging traceSpecification="*=info:com.ibm.ws.security.*=all:Authentication=all:com.ibm.ws.container.service.security.internal.*=all" />
</server>

View File

@ -7,6 +7,7 @@ liberty {
server {
name = 'player-service'
dropins = [war]
configDirectory = file('src/main/liberty/config')
bootstrapProperties = ['httpPort': httpPort, 'httpsPort': httpsPort]
}
}

View File

@ -17,7 +17,7 @@ public class PlayerDB {
/**
* Inserts a new player into the database.
*
*
* @return Returns true if the player was created. False if a player with the same ID already existed
*/
public boolean create(Player p) {
@ -56,4 +56,8 @@ public class PlayerDB {
return numPlayersAhead + 1;
}
public boolean exists(String id) {
return allPlayers.containsKey(id);
}
}

View File

@ -31,7 +31,7 @@ public class Player {
@JsonbCreator
public Player(String name, String id) {
this.id = id == null ? DOMAIN.BASIC + name : id;
this.id = (id == null || id.equals("null")) ? DOMAIN.BASIC + name : id;
this.name = name;
}

View File

@ -1,9 +1,11 @@
package org.libertybikes.player.service;
import java.util.Collection;
import java.util.HashMap;
import java.util.Random;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
@ -14,6 +16,8 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.libertybikes.player.data.PlayerDB;
@Path("/player")
@ -23,6 +27,19 @@ public class PlayerService {
@Inject
PlayerDB db;
@Resource(lookup = "jwtKeyStore")
protected String keyStore;
@Inject
@ConfigProperty(name = "jwtKeyStorePassword", defaultValue = "secret2")
String keyStorePW;
@Inject
@ConfigProperty(name = "jwtKeyStoreAlias", defaultValue = "rebike")
String keyStoreAlias;
@Inject
private JsonWebToken callerPrincipal;
@PostConstruct
public void initPlayers() {
// TODO use MP-Config to only run this for local dev mode
@ -87,4 +104,23 @@ public class PlayerService {
db.update(p);
System.out.println(p);
}
@GET
@Path("/getJWTInfo")
@Produces("application/json")
public HashMap<String, String> getJWTInfo() {
HashMap<String, String> map = new HashMap<String, String>();
String id = callerPrincipal.getClaim("id");
if (db.exists(id)) {
map.put("exists", "true");
map.put("username", db.get(id).name);
} else {
map.put("exists", "false");
}
map.put("id", id);
return map;
}
}

View File

@ -5,7 +5,30 @@
<feature>jsonb-1.0</feature>
</featureManager>
<applicationManager autoExpand="true"/>
<sslDefault sslRef="RpSSLConfig" />
<ssl
id="RpSSLConfig"
keyStoreRef="validationKeystore"
trustStoreRef="validationKeystore" />
<keyStore
id="validationKeystore"
password="secret2"
type="jks"
location="${server.config.dir}resources/security/validationKeystore.jks" />
<jndiEntry jndiName="jwtKeyStore" value="${server.config.dir}resources/security/validationKeystore.jks"/>
<mpJwt
id="myMpJwt"
keyName="rebike"
issuer="https://accounts.google.com"
audiences="client">
</mpJwt>
<httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="${httpPort}" httpsPort="${httpsPort}" />
<applicationManager autoExpand="true"/>
<logging traceSpecification="*=info:com.ibm.ws.security.*=all:Authentication=all:com.ibm.ws.container.service.security.internal.*=all" />
</server>