mirror of
https://github.com/OpenLiberty/liberty-bikes.git
synced 2025-01-18 10:23:58 +08:00
add jwt between game and player service
This commit is contained in:
parent
0f0cfaa2ed
commit
18d4e3365e
@ -1,5 +1,6 @@
|
||||
dependencies {
|
||||
compileOnly group: 'javax.websocket', name: 'javax.websocket-api', version: '1.1'
|
||||
compile group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.0'
|
||||
}
|
||||
|
||||
ext {
|
||||
@ -17,6 +18,7 @@ liberty {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
libertyStart.doLast {
|
||||
println "Application available at: http://localhost:${httpPort}/"
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,13 @@ package org.libertybikes.game.core;
|
||||
import static org.libertybikes.game.round.service.GameRoundWebsocket.sendToClient;
|
||||
import static org.libertybikes.game.round.service.GameRoundWebsocket.sendToClients;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyStore;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
@ -31,6 +36,10 @@ import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
import org.libertybikes.game.core.Player.STATUS;
|
||||
import org.libertybikes.restclient.PlayerService;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
|
||||
@JsonbPropertyOrder({ "id", "gameState", "board", "nextRoundId" })
|
||||
public class GameRound implements Runnable {
|
||||
|
||||
@ -66,8 +75,18 @@ public class GameRound implements Runnable {
|
||||
private LobbyCountdown lobbyCountdown;
|
||||
private AtomicBoolean lobbyCountdownStarted = new AtomicBoolean();
|
||||
|
||||
private String jwt = null;
|
||||
|
||||
private int ticksFromGameEnd = 0;
|
||||
|
||||
protected static Key signingKey = null;
|
||||
|
||||
protected String keyStore;
|
||||
|
||||
String keyStorePW;
|
||||
|
||||
String keyStoreAlias;
|
||||
|
||||
// Get a string of 4 random uppercase letters (A-Z)
|
||||
private static String getRandomId() {
|
||||
char[] chars = new char[4];
|
||||
@ -266,18 +285,95 @@ public class GameRound implements Runnable {
|
||||
|
||||
private void updatePlayerStats() {
|
||||
if (gameState != State.FINISHED)
|
||||
throw new IllegalStateException("Canot update player stats while game is still running.");
|
||||
throw new IllegalStateException("Cannot update player stats while game is still running.");
|
||||
|
||||
PlayerService playerSvc = CDI.current().select(PlayerService.class, RestClient.LITERAL).get();
|
||||
int rank = 1;
|
||||
for (Player p : playerRanks) {
|
||||
log("Player " + p.name + " came in place " + rank);
|
||||
if (p.isRealPlayer())
|
||||
playerSvc.recordGame(p.id, rank);
|
||||
if (p.isRealPlayer()) {
|
||||
String jwt = createJWT();
|
||||
String authHeader = "Bearer " + jwt;
|
||||
playerSvc.recordGame(p.id, rank, authHeader);
|
||||
}
|
||||
rank++;
|
||||
}
|
||||
}
|
||||
|
||||
private String createJWT() {
|
||||
if (jwt != null)
|
||||
return jwt;
|
||||
if (signingKey == null) {
|
||||
try {
|
||||
getKeyStoreInfo();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Claims onwardsClaims = Jwts.claims();
|
||||
|
||||
onwardsClaims.put("upn", "game-service");
|
||||
onwardsClaims.put("groups", "admin");
|
||||
// Set the subject using the "id" field from our claims map.
|
||||
onwardsClaims.setSubject(id);
|
||||
|
||||
onwardsClaims.setId(id);
|
||||
|
||||
// We'll use this claim to know this is a user token
|
||||
onwardsClaims.setAudience("client");
|
||||
|
||||
onwardsClaims.setIssuer("https://game-service-libertybikes.mybluemix.net");
|
||||
// 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, 48);
|
||||
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.
|
||||
jwt = Jwts.builder()
|
||||
.setHeaderParam("kid", "bike")
|
||||
.setHeaderParam("alg", "RS256")
|
||||
.setClaims(onwardsClaims)
|
||||
.signWith(SignatureAlgorithm.RS256, signingKey)
|
||||
.compact();
|
||||
return jwt;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "bad";
|
||||
}
|
||||
|
||||
private synchronized void getKeyStoreInfo() throws IOException {
|
||||
if (signingKey != null)
|
||||
return;
|
||||
try {
|
||||
// load up the keystore
|
||||
|
||||
keyStore = InitialContext.doLookup("jwtKeyStore");
|
||||
keyStorePW = InitialContext.doLookup("jwtKeyStorePassword");
|
||||
keyStoreAlias = InitialContext.doLookup("jwtKeyStoreAlias");
|
||||
|
||||
FileInputStream is = new FileInputStream(keyStore);
|
||||
|
||||
KeyStore signingKeystore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
signingKeystore.load(is, keyStorePW.toCharArray());
|
||||
signingKey = signingKeystore.getKey(keyStoreAlias, keyStorePW.toCharArray());
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void gameTick() {
|
||||
if (gameState != State.RUNNING) {
|
||||
ticksFromGameEnd++;
|
||||
|
@ -2,6 +2,7 @@ package org.libertybikes.restclient;
|
||||
|
||||
import javax.enterprise.context.Dependent;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
@ -23,6 +24,6 @@ public interface PlayerService {
|
||||
|
||||
@POST
|
||||
@Path("/rank/{playerId}/recordGame")
|
||||
public void recordGame(@PathParam("playerId") String id, @QueryParam("place") int place);
|
||||
public void recordGame(@PathParam("playerId") String id, @QueryParam("place") int place, @HeaderParam("Authorization") String token);
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,10 @@
|
||||
<jndiEntry jndiName="round/gameSpeed" value="50"/> <!-- Default = 50(ms) -->
|
||||
<jndiEntry jndiName="round/map" value="-1"/> <!-- Default = -1 (random map) -->
|
||||
<jndiEntry jndiName="round/autoStartCooldown" value="20"/> <!-- Default = 20(sec) -->
|
||||
<jndiEntry jndiName="jwtKeyStore" value="${server.config.dir}resources/security/validationKeystore.jks"/>
|
||||
<jndiEntry jndiName="jwtKeyStorePassword" value="secret2"/>
|
||||
<jndiEntry jndiName="jwtKeyStoreAlias" value="bike2"/>
|
||||
|
||||
|
||||
<applicationManager autoExpand="true"/>
|
||||
|
||||
|
@ -15,6 +15,9 @@ liberty {
|
||||
libertyStart.doLast {
|
||||
println "Application available at: http://localhost:${httpPort}/${project.name}"
|
||||
}
|
||||
dependencies {
|
||||
compile group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.0'
|
||||
}
|
||||
|
||||
task open {
|
||||
doLast {
|
||||
|
@ -5,9 +5,11 @@ import java.util.Collections;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
@ -68,8 +70,13 @@ public class RankingService {
|
||||
}
|
||||
|
||||
@POST
|
||||
@RolesAllowed({ "admin" })
|
||||
@Path("/{playerId}/recordGame")
|
||||
public void recordGame(@PathParam("playerId") String id, @QueryParam("place") int place) {
|
||||
public void recordGame(@PathParam("playerId") String id, @QueryParam("place") int place, @HeaderParam("Authorization") String token) {
|
||||
recordGame(id, place);
|
||||
}
|
||||
|
||||
public void recordGame(String id, int place) {
|
||||
if (place < 0 || place > 4) {
|
||||
System.out.println("Invalid place (" + place + "), must be 0-4");
|
||||
return;
|
||||
|
@ -22,10 +22,10 @@
|
||||
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://auth-service-libertybikes.mybluemix.net"
|
||||
|
||||
<mpJwt id="myMpJwt"
|
||||
keyName="bike2"
|
||||
issuer="https://game-service-libertybikes.mybluemix.net"
|
||||
audiences="client"/>
|
||||
|
||||
<httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="${httpPort}" httpsPort="${httpsPort}" />
|
||||
|
Loading…
Reference in New Issue
Block a user