Skip to main content

Remote service interaction with Versile and Groovy - Part 2

In the previous post I showed you how to connect two peers using Versile. In this post I'll show how to authenticate the party requesting the connection.

Authentication in Versile is done by checking the public key received from the other party. Both sides can check the identity of the other side. Identity key pairs can be generated using Versile Decentral Identity (VDI), which in many ways is similar to SSH-keygen. Using VDI is as simple as usernames and passwords, but not having to share this with the other party increase security - and the keys can be exchanged privately between the two parties, no certificate authority needs to be involved.

A Versile Decentral Identity can be generated from Groovy/Java as simple as this:


VPrivateCredentials key = new VPrivateCredentials(VDecentralIdentity.dia(1024, 'versilegroovy', 'peter', 'asdfghjkl12345'))

And we can print the public key:

print new String(key.getKeyPair().exportPublicArmoredPkcs())

Resulting in the following: 

-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALJSfQufrjoA3CwQ+xxAc3oYtobAjCFaGFf1b/JnBzYavzvuAQRO5VhtIXQu4MtuYGXS
J0Uv26h79JwGR1RwlzR75adviWrBsNhI6bER7Un64YWzb+ZyqsVAbQppvlUUjB0D9yrM5ktSSxmu
NQDS/clV3Datn6YKMiFwqI5KqtehAgMBAAE=
-----END RSA PUBLIC KEY-----

This key we'll give to the other party so that it will recognize the identity trying to connect:

final RSAPublicKey authorizedKey = VRSAKeyPair.importPublicArmored(authorizedKeyString.getBytes());

(where authorizedKeyString is the public key string above)

Then we'll set up the Versile service to check the received credentials:

service = new VOPService(new GW(),credentials,new VLinkAuth(new VAuth(true,false) {
   
   // Check client credentials
   public synchronized boolean acceptCredentials(VCredentials credentials) {
if(authorizedKey.equals(credentials.getPublicKey())) {
   println "Accepted key"
   return true
} else {
   println "Rejected key"
   return false
}
   }
}));

When connecting to the service from the other side we'll have to provide the key:

proxy = VUrl.resolve("vop://localhost/",key)

The full server code then looks like this:

import org.versile.Versile
import org.versile.reactor.service.VOPService
import org.versile.orb.service.VGatewayFactory
import org.versile.orb.entity.VObject
import org.versile.orb.external.VExternal
import org.versile.orb.external.Publish
import org.versile.common.auth.VPrivateCredentials;
import org.versile.crypto.VDecentralIdentity;
import org.versile.common.auth.VAuth
import org.versile.orb.link.VLinkAuth
import org.versile.common.auth.VCredentials
import java.security.interfaces.RSAPublicKey
import org.versile.crypto.VRSAKeyPair

Versile.setInternalUseAGPL() // Use AGPL License

// Business service
class Svc extends VExternal {
    @Publish(show=true, ctx=false) public String hello(String name) {
return "hello "+name
    }    
}
// A service gateway to be connected to a VOPService listener
class GW implements VGatewayFactory {    
    public VObject build() {
return new Svc()
    }
}
// Create server identification credentials
key = VDecentralIdentity.dia(1024, "", "", "someServerPwd");
credentials = new VPrivateCredentials(key);

// This is the key we will accept from the client
String authorizedKeyString =   "-----BEGIN RSA PUBLIC KEY-----\n"+
   "MIGJAoGBALJSfQufrjoA3CwQ+xxAc3oYtobAjCFaGFf1b/JnBzYavzvuAQRO5VhtIXQu4MtuYGXS\n"+
   "J0Uv26h79JwGR1RwlzR75adviWrBsNhI6bER7Un64YWzb+ZyqsVAbQppvlUUjB0D9yrM5ktSSxmu\n"+
   "NQDS/clV3Datn6YKMiFwqI5KqtehAgMBAAE=\n"+
   "-----END RSA PUBLIC KEY-----";

final RSAPublicKey authorizedKey = VRSAKeyPair.importPublicArmored(authorizedKeyString.getBytes());

// Create the service using the gateway and credentials, and require key authentication
service = new VOPService(new GW(),credentials,new VLinkAuth(new VAuth(true,false) {
   
   // Check client credentials
   public synchronized boolean acceptCredentials(VCredentials credentials) {
if(authorizedKey.equals(credentials.getPublicKey())) {
   println "Accepted key"
   return true
} else {
   println "Rejected key"
   return false
}
   }
}));

// Start the service
service.start()

And the client:

import org.versile.Versile
import org.versile.reactor.url.VUrl
import org.versile.orb.entity.VProxy
import org.versile.common.auth.VPrivateCredentials
import org.versile.crypto.VDecentralIdentity
import org.versile.crypto.VRSAKeyPair

// Select license
Versile.setInternalUseAGPL()

// Let's be able to call methods directly on the VProxy object, rather than using call method
VProxy.metaClass.methodMissing = {String name,args -> 
    return delegate.call(name,args)    
}

// Create credentials
VPrivateCredentials key = new VPrivateCredentials(VDecentralIdentity.dia(1024, 'versilegroovy', 'peter', 'asdfghjkl12345'))
// Print public key, this we have inserted on the server side as the authorized key
print new String(key.getKeyPair().exportPublicArmoredPkcs())

// Get remote object, and pass the key
proxy = VUrl.resolve("vop://localhost/",key)

// Call method on remote object
print proxy.hello("Peter")

Comments

Popular posts from this blog

Angular components not reloading on route change

Spent a long time wondering why route changes caused strange effects on my component, and found out that it was because my component wasn't reloading at all. I had this assumption that when a route parameter changed (e.g. /projects/1 changed to /projects/2 ) the component for the route would be reloaded. But this is not the default behaviour of the Angular router. The default behaviour of the Angular router is to reuse the route if the configuration is the same (and not reload the component). But we can override this by providing a RouteReuseStrategy to our @NgModule: providers: [ { provide: RouteReuseStrategy, useClass: AARouteReuseStrategy } ] The full custom implementation of the RouteReuseStrategy will then be like this (and it's the shouldReuseRoute method that changes the behaviour so that the component is reloaded on route parameter change): export class AARouteReuseStrategy extends RouteReuseStrategy { shouldDetach(route: ActivatedRou...

Using Angular i18n translation strings outside templates

As of today in Angular 6 i18n is only available in the templates. So what if we want to use translated messages programatically and outside templates? I still use the component template html file to declare the message to be translated, but by obtaining the TemplateRef ViewChild in the component typescript file I can get the translated messages from typescript. <ng-template #boardInvitationEmailBody let-organization="organization" let-url="url"> <ng-container i18n>You have been invited to join the board portal for</ng-container> {{organization}}. <ng-container i18n> Please follow the link to: </ng-container> {{url}} </ng-template> So in the typescript code i can now call the createEmailBodyTranlated text method to get the translated text for use outside the template. @ViewChild('boardInvitationEmailBody') boardInvitationEmailBody: TemplateRef ; createEmailBodyTranslatedText(org...

Using GIT for offline web app syncing and storage

Offline web applications, progressive web apps (PWA) using service workers for being available offline also needs a way to sync changes with the server. Mostly we store data in JSON documents, and we could identify changes per line - which is something GIT is excellent at. So how could we make the browser a GIT client? I've been working on this for some months now, and compiled libgit2 to webassembly using emscripten - and it turns out to work very well. Some video demos: Cloning a repository: https://youtu.be/rcBluzpUWE4 Merging of file changes: https://youtu.be/xfGrMwLy_tw The project is here: https://github.com/fintechneo/angular-git-filebrowser