Old server-side code samplesΒΆ
Server
@RestController
public class ProcController implements ExternalAuthenticateHandler, MutualAuthenticateHandler {
/* This is the private key for SCWS environment creation
* (should correspond to the public key for which the webappcert has been generated)
* Note: the webappcert is in the javascript code */
private static final String privateKeyPEM =
"-----BEGIN RSA PRIVATE KEY-----\r\n" +
"MIIBOgIBAAJBAMPMNNpbZZddeT/GTjU0PWuuN9VEGpxXJTAkmZY02o8238fQ2ynt\r\n" +
"N40FVl08YksWBO/74XEjU30mAjuaz/FB2kkCAwEAAQJBALoMlsROSLCWD5q8EqCX\r\n" +
"rS1e9IrgFfEtFZczkAWc33lo3FnFeFTXSMVCloNCBWU35od4zTOhdRPAWpQ1Mzxi\r\n" +
"aCkCIQD9qjKjNvbDXjUcCNqdiJxPDlPGpa78yzyCCUA/+TNwVwIhAMWZoqZO3eWq\r\n" +
"SCBTLelVQsg6CwJh9W7vlezvWxUni+ZfAiAopBAg3jmC66EOsMx12OFSOTVq6jiy\r\n" +
"/8zd+KV2mnKHWQIgVpZiLZo1piQeAvwwDCUuZGr61Ap08C3QdsjUEssHhOUCIBee\r\n" +
"72JZuJeABcv7lHhAWzsiCddVAkdnZKUo6ubaxw3u\r\n" +
"-----END RSA PRIVATE KEY-----";
/**
* Entry point for generating the signature, for the initial environment creation.
* (called by the client between SCWS.findService and SCWS.createEnvironment).
* @param rnd the challenge to sign (coming from the client-side SCWS).
* @return the cryptogram that will authorize environment creation.
*/
@GetMapping("/sign_env_challenge")
public String signEnvChallenge(String rnd) {
try {
PrivateKey privateKey;
try (PEMParser pemParser = new PEMParser(new StringReader(privateKeyPEM))) {
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
Object object = pemParser.readObject();
KeyPair kp = converter.getKeyPair((PEMKeyPair)object);
privateKey = kp.getPrivate();
}
Signature signer = Signature.getInstance("NONEwithRSA","BC");
signer.initSign(privateKey);
signer.update(Hex.decode(rnd));
byte[] signature = signer.sign();
return Hex.toHexString(signature);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage(), e);
}
}
/**
* Create a {@link SCSSSession} object.
* @return the handle of created {@link SCSSSession} object.
* @throws SCMException
* @throws IOException
*/
@GetMapping("/init_session")
public String startTest() throws SCMException, IOException {
final SCSSSession s = new SCSSSession();
return s.getHandle();
}
/**
* Process session and allow communication between ServerSide SmartCard and ClientSide SmartCard middlewares.
* @param id the handle of the {@link SCSSSession} object to communicate with.
* @param body the body of HTTP request
* @return the result of processed session.
* @throws SCMException
* @throws IOException
*/
@PostMapping("/process_session/{id}")
public String processSession(@PathVariable String id, @RequestBody String body) throws SCMException, IOException {
return SCSSSession.process(id, body);
}
/**
* Execute session. Once {@link SCSSSession} object is created and session is managed with {@link SCSSSession#process}, call this to use methods and attributes from
* {@link Token} object.
* @param id the handle of {@link SCSSSession} object.
* @return some result
* @throws SCMException
* @throws IOException
*/
@GetMapping("/exec_session/{id}")
public String execSession(@PathVariable String id) throws SCMException, IOException {
SCSSSession s = SCSSSession.getSession(id);
try {
s.init();
/* -------------------------------------------------------------------- */
// here lies the server-side application logic.
// Operations are made by calling Token methods on the `s` object.
/* -------------------------------------------------------------------- */
}
catch (Exception e){
return "Operation failed";
}
finally {
s.close();
}
return "Operation OK";
}
}
Client
window.webappcert = "4SyF8E6?J4{SVYI)psu*Xb0t#E=1oJdCH}B[Y8){oDbd%GP-L&ZI*KtJl@P?<:t$Tvv[NPS9>6Mqkpnmg^O1Zkn[Zo#czsNjEe:ASWVef!l-I$=e02=*YAmCkmvm1iifG])b[EFTe2>-:Hmk.KPTX9S0CQPVV41h3>S0>QyDEq/Bb?u#Zc^i7v]JDE@jgy@*bbc=59z!woxg6nRpqTxix&o8>5J8D6lzoLkuw=Q8MreUlGfHfBt(&q8!8Eh>BBL.6A)S.&IBkyKcR%$V@Zb$.!0aJjM1<iEMzoN)2!j^GtkU:d>A/Rx=u*@Q7W6$kk[zM";
window.connections = [];
window.connecting = false;
/* boilerplate function for performing a ajax request */
function req(method, url, contents) {
return new Promise(function(resolve, reject) {
var req = new XMLHttpRequest();
req.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200)
resolve(req.responseText);
else
reject(new Error("App server request failed"));
}
};
req.open(method, url, true);
req.send(contents);
});
}
function reqGet(url) {
return req("GET", url);
}
function reqPost(url, contents) {
return req("POST", url, contents);
}
/* connects to the SCWS, then tries to find smart cards in readers and connect to them */
function init() {
/* connecting to SCWS */
console.log("Connecting to SCWS...");
SCWS.findService(window.webappcert).then(function(challenge) {
console.log("Connection to SCWS succeeded");
return reqGet("sign_env_challenge?rnd=" + challenge)
.then(function(signature) {
return SCWS.createEnvironment(signature);
});
}).then(function() {
console.log("SCWS environment created successfully");
/* check all readers already connected */
var readers = SCWS.readers;
if (readers.length == 0) {
console.log("No readers found");
}
else {
for (var i = 0; i < readers.length; i++)
checkReader(readers[i]);
}
document.getElementById("initbtn").style.display = "none";
updateStatus();
/* register event callbacks for checking readers changes */
SCWS.onreaderadded = function(reader) {
console.log("Reader inserted: '" + reader.name + "'");
checkReader(reader);
}
SCWS.onreaderremoved = function(reader) {
console.log("Reader removed: '" + reader.name + "'");
checkReader(reader);
}
SCWS.onreaderstatechanged = function(reader) {
console.log("Reader state changed: '" + reader.name + "'");
checkReader(reader);
}
}).catch(function(err) {
console.log("ERROR: " + err.message);
});
}
function updateStatus()
{
// update GUI elements to show connection state
}
/**
* Called when a reader needs to be scanned for objects.
*/
function checkReader(reader) {
/* trying to find reader from existing connections */
for (var connidx = 0; connidx < window.connections.length; connidx++) {
if (window.connections[connidx].reader == reader)
break;
}
if (connidx == window.connections.length) {
if (reader.status == "ok" && reader.cardPresent) {
/* reader not found in existing connections, and reader contains card: connecting */
console.log("Connecting to reader '" + reader.name + "'...");
var connection = { reader: reader };
window.connections.push(connection);
window.connecting = true;
updateStatus();
reader.connect().then(function(token) {
connection.token = token;
connection.items = [];
console.log("Getting objects from reader '" + reader.name + "'...");
return token.getObjects();
}).then(function(items) {
connection.items = items;
window.connecting = false;
updateStatus();
}).catch(function(err) {
console.log("ERROR: " + err.message);
window.connecting = false;
updateStatus();
});
}
}
else {
var conn = connections[connidx];
if (reader.status != "ok" || !reader.cardPresent) {
/* reader found in existing connections, but contains no card: removing */
if (conn.token) {
console.log("Disconnecting from reader '" + reader.name + "'.");
conn.token.disconnect();
}
window.connections.splice(connidx, 1);
updateStatus();
}
}
}
function showError(err) {
document.getElementById("errmsg").textContent = err.message || err;
}
/* Function that actually opens the server session */
function test() {
/* first, create the SCSSSession instance on the server */
reqGet("init_session").then(function(sessHandle) {
/* process the session (session handle is used in the URL) */
window.connections[0].token.processServerSession("process_session/" + sessHandle).then(function() {
console.log("OK");
/* at that point, the session is fully completed */
}, function() {
console.log("error");
});
/* concurrently with the processServerSession call, the REST entry point that actually performs the operation is called, also giving the session handle */
reqGet("exec_session/" + sessHandle).then(function(result) {
console.log(result);
/* although the REST operation is completed, the session may not be yet finished at that point */
});
});
}