mirror of
https://github.com/OpenLiberty/liberty-bikes.git
synced 2025-03-07 11:26:52 +08:00
login
This commit is contained in:
parent
32974d8ff5
commit
180c6f000f
@ -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'
|
||||
}
|
||||
|
||||
|
||||
|
@ -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";
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
|
||||
}
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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>
|
@ -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>
|
@ -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'}
|
||||
|
@ -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>
|
||||
|
@ -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() {
|
||||
|
@ -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/']
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
BIN
game-service/src/main/liberty/config/resources/security/key.jks
Normal file
BIN
game-service/src/main/liberty/config/resources/security/key.jks
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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>
|
@ -7,6 +7,7 @@ liberty {
|
||||
server {
|
||||
name = 'player-service'
|
||||
dropins = [war]
|
||||
configDirectory = file('src/main/liberty/config')
|
||||
bootstrapProperties = ['httpPort': httpPort, 'httpsPort': httpsPort]
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
Loading…
Reference in New Issue
Block a user