Skip to content

Added JNDI keystore support for key pairs #10

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
10 changes: 3 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,7 @@ The folder test-keystore is used for testing and should not be used for any prod

```
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST -d '{"controller":"com.microlib.controller.JwtService" , "action":"getToken"}' http://localhost:9000
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST -d '{"controller":"com.microlib.controller.JwtService" , "action":"createAndSignToken", "key-id":"test-keystore"}' http://localhost:9000
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST -d '{"controller":"com.microlib.controller.JwtService" , "action":"verifyToken", "key-id":"test-keystore" , "token": "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.gF-JDds389H5l4tk2o7qpuSIzSAEgjfVwTb7c3Tf1InuD7EWk5gjY4kKPP__MGc39HfOobjqUMsUFAJBAJYOJxKmfLMBCLr5TXMMeLcc3-qZw3NZ0DDhq76yLiVA_P3pBm1k-kKtZQvwRY8VrLN9JfBm0BDy3f2wvNRmDXQLHAU33fi4zACpGcTJ9TfNBoY84sOGUBhd73yxPLr4lBhYrFjcqGboZDNzg2LdisTVP1I_9KlHA4d8-H5LHYOcwiFD-hFZteKl52jslKfNucHgrhn0D1iLf4YiE92yNVobLAkVN_qPG8ZX8sNlA5AahIqKenk6hK_C0f1LTGzc6ZxXMA"}' http://localhost:9000
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST -d '{"controller":"com.microlib.controller.JwtService" , "action":"createAndSignToken", "key-id":"test"}' http://localhost:9000
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST -d '{"controller":"com.microlib.controller.JwtService" , "action":"verifyToken", "key-id":"test" , "token": "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.gF-JDds389H5l4tk2o7qpuSIzSAEgjfVwTb7c3Tf1InuD7EWk5gjY4kKPP__MGc39HfOobjqUMsUFAJBAJYOJxKmfLMBCLr5TXMMeLcc3-qZw3NZ0DDhq76yLiVA_P3pBm1k-kKtZQvwRY8VrLN9JfBm0BDy3f2wvNRmDXQLHAU33fi4zACpGcTJ9TfNBoY84sOGUBhd73yxPLr4lBhYrFjcqGboZDNzg2LdisTVP1I_9KlHA4d8-H5LHYOcwiFD-hFZteKl52jslKfNucHgrhn0D1iLf4YiE92yNVobLAkVN_qPG8ZX8sNlA5AahIqKenk6hK_C0f1LTGzc6ZxXMA"}' http://localhost:9000

```

## Improvements

Read all key pairs into memory at server startup
```
File renamed without changes.
File renamed without changes.
Binary file added app-keystore/mongodb/private_key.der
Binary file not shown.
Binary file added app-keystore/mongodb/public_key.der
Binary file not shown.
File renamed without changes.
File renamed without changes.
Binary file added app-keystore/test/private_key.der
Binary file not shown.
File renamed without changes.
Binary file added app-keystore/test/public_key.der
Binary file not shown.
Binary file added app-keystore/usermanager/private_key.der
Binary file not shown.
Binary file added app-keystore/usermanager/public_key.der
Binary file not shown.
8 changes: 4 additions & 4 deletions make.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,24 @@ function usage() {
function clean() {
rm -rf classes/com/*
echo "Task : [clean] completed"
echo " "
echo " "
}

function compile() {
find src/ -name \*.java -print > file.list
find src/ -name \*.java -print > file.list
javac -g -d classes -cp $CP @file.list
echo "Task : [compile] completed"
cp src/com/microlib/server/*.properties classes/com/microlib/server/
cp src/com/microlib/jndi/service/*.properties classes/com/microlib/jndi/service/
cp src/*.properties classes/
echo "Task : [copying resources] completed"
echo " "
echo " "
}

function run() {
java -cp $CP com.microlib.server.TheServer 9000 100
echo "Task : [run] completed"
echo " "
echo " "
}


Expand Down
71 changes: 49 additions & 22 deletions src/com/microlib/controller/JwtService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,30 @@
import com.auth0.jwt.*;
import com.auth0.jwt.algorithms.*;
import com.auth0.jwt.exceptions.*;
import java.nio.file.*;
import java.io.*;
import java.security.*;
import java.security.spec.*;
import java.security.interfaces.*;
import org.apache.commons.logging.*;
import org.apache.commons.logging.impl.*;
import java.util.Map;
import java.util.List;
import java.util.Map;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import com.microlib.dataformat.*;
import com.microlib.jndi.service.*;
import java.io.UnsupportedEncodingException;
import javax.naming.NamingException;

public class JwtService implements ExecInterface {

int nLoop = 0;
private boolean bRunning = false;
private String name;
private static org.apache.commons.logging.Log log;
final static String jndiName = "java/KeyStore";
private KeyPairStoreImpl keyStore;


public boolean isRunning() {
return bRunning;
Expand Down Expand Up @@ -56,36 +63,48 @@ public String doProcess(Map<String, Object> map) {
// create a token with our generated private rsa key
// use the key-id to retrieve the correct kea
if (null == map.get("key-id")) {
log.error("no key-id found ");
response = json.message("ERROR no key-id found ", "KO");
} else {
byte[] keyBytes = Files.readAllBytes(new File(map.get("key-id").toString() + "/private_key.der").toPath());
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPrivateKey key = (RSAPrivateKey) kf.generatePrivate(spec);
String token = JWT.create().withIssuer("auth0").sign(Algorithm.RSA256(key));
log.info("Signed Token : " + token);
response = json.message("Signed Token " + token, "OK");
byte[] keyBytes = keyStore.getPrivateByteArray(map.get("key-id").toString());
if (null == keyBytes) {
log.error("key-id " + map.get("key-id").toString() + " not found");
response = json.message("ERROR key-id " + map.get("key-id").toString() + " not found ", "KO");
} else {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPrivateKey key = (RSAPrivateKey) kf.generatePrivate(spec);
String token = JWT.create().withIssuer("auth0").sign(Algorithm.RSA256(key));
log.info("Signed Token : " + token);
response = json.message("Signed Token " + token, "OK");
}
}
} catch (JWTCreationException | IOException | NoSuchAlgorithmException | InvalidKeySpecException exception) {
} catch (JWTCreationException | NoSuchAlgorithmException | InvalidKeySpecException exception) {
log.error(exception);
response = json.message("ERROR " + exception.toString(), "KO");
}
} else if (map.get("action").toString().equals("verifyToken")) {
try {
if (null == map.get("key-id")) {
log.error("no key-id found ");
response = json.message("ERROR no key-id found ", "KO");
} else {
byte[] keyBytes = Files.readAllBytes(new File(map.get("key-id").toString() + "/public_key.der").toPath());
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPublicKey key = (RSAPublicKey) kf.generatePublic(spec);
String token = map.get("token").toString();
JWTVerifier verifier = JWT.require(Algorithm.RSA256(key)).withIssuer("auth0").build();
JWT jwt = (JWT) verifier.verify(token);
log.info("Token verified " + jwt);
response = json.message("Token verified ", "OK");
byte[] keyBytes = keyStore.getPublicByteArray(map.get("key-id").toString());
if (null == keyBytes) {
log.error("key-id " + map.get("key-id").toString() + " not found");
response = json.message("ERROR key-id " + map.get("key-id").toString() + " not found ", "KO");
} else {
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPublicKey key = (RSAPublicKey) kf.generatePublic(spec);
String token = map.get("token").toString();
JWTVerifier verifier = JWT.require(Algorithm.RSA256(key)).withIssuer("auth0").build();
JWT jwt = (JWT) verifier.verify(token);
log.info("Token verified " + jwt);
response = json.message("Token verified ", "OK");
}
}
} catch (JWTVerificationException | JWTCreationException | IOException | NoSuchAlgorithmException
} catch (JWTVerificationException | JWTCreationException | NoSuchAlgorithmException
| InvalidKeySpecException exception) {
log.error(exception);
response = json.message("ERROR " + exception.toString(), "KO");
Expand All @@ -97,6 +116,14 @@ public String doProcess(Map<String, Object> map) {
}

public void init(String sIn) {
log = LogFactory.getLog(JwtService.class);
try {
log = LogFactory.getLog(JwtService.class);
Hashtable<String, String> ht = new Hashtable<String, String>();
ht.put("java.naming.factory.initial", "com.microlib.jndi.DSInitCtxFactory");
Context ctx = new InitialContext(ht);
keyStore = (KeyPairStoreImpl) ctx.lookup(jndiName);
} catch(NamingException e) {
// we can't assume that the log is available
}
}
}
2 changes: 1 addition & 1 deletion src/com/microlib/jndi/service/JndiInterface.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* @author: Luigi Mario Zuccarelli
* @version: 1.10
* @date: Generated on Mon Dec 29 15:30:20 CEST 2014
* @file: PluginInterface.java
* @file: JndiInterface.java
*
*/

Expand Down
74 changes: 74 additions & 0 deletions src/com/microlib/jndi/service/KeyPairStoreImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.microlib.jndi.service;


import org.apache.commons.logging.*;
import org.apache.commons.logging.impl.*;
import java.util.*;
import java.nio.file.*;
import java.io.*;

/**
* @(#) KeyPairStoreImpl
*
* In the light of open source software you are free to do what you like with this code.
* Redistribution and use in source and binary forms, with or without
* modification, is absolutely permitted - just keep the credits please.
*
* @author: Luigi Mario Zuccarelli
* @version: 1.10
* @date: Generated on Mon Dec 29 15:30:20 CEST 2014
* @file: KeyPairStoreImpl.java
*
*
*
* Tags for CVS
* $Author$
* $Id$
* $Date$
*
*/

public class KeyPairStoreImpl implements JndiInterface {

private static org.apache.commons.logging.Log log;
private Map<String, byte[]> publicKeyStore = new HashMap<String, byte[]>();
private Map<String, byte[]> privateKeyStore = new HashMap<String, byte[]>();

public KeyPairStoreImpl() {
log = LogFactory.getLog(KeyPairStoreImpl.class);
}

public void init(String sIn) {

try {
File[] directories = new File("app-keystore").listFiles(File::isDirectory);
for (File f : directories) {
log.info("Loading keypair for " + f.getName());
privateKeyStore.put(f.getName(), Files.readAllBytes(new File(f.getPath() + "/private_key.der").toPath()));
publicKeyStore.put(f.getName(), Files.readAllBytes(new File(f.getPath() + "/public_key.der").toPath()));
}
} catch (IOException io) {
log.error(io);
}
}

public byte[] getPrivateByteArray(String sIn) {
return privateKeyStore.get(sIn);
}

public byte[] getPublicByteArray(String sIn) {
return publicKeyStore.get(sIn);
}

public void destroy() {
try {
log.info(" ");
privateKeyStore = null;
publicKeyStore = null;
} catch (Exception e) {
log.error(e);
} finally {
log = null;
}
}
}
2 changes: 1 addition & 1 deletion src/com/microlib/server/TheServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public TheServer(int port, int threads) {
log.info(" ");
log.info("Press CTRL-C to gracefully shutdown the server ");
log.info(" ");
log.info(" ");

while (!bStop) {
Socket socket = listener.accept();
Expand Down Expand Up @@ -128,5 +129,4 @@ public void run() {
}
}
}

}
7 changes: 6 additions & 1 deletion src/com/microlib/server/TheServer.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# plugins [service list]

jndiplugin.count=11
jndiplugin.count=12

# BasicDataSourceImpl
name.0=com.microlib.jndi.service.BasicDataSourceImpl
Expand Down Expand Up @@ -71,3 +71,8 @@ use.10=true
value.10=0
jndi.10=java/Scheduler

# KeyPairStoreImpl
name.11=com.microlib.jndi.service.KeyPairStoreImpl
use.11=true
value.11=0
jndi.11=java/KeyStore