
Authentication
Most, if not all, Lightstreamer applications will, at some point, require some sort of authentication mechanism to validate their users. Moreover, there usually is an authentication mechanism already in place when Lightstreamer is introduced in the system.So, let's see how to introduce Lightstreamer in an environment where Authentication is already handled by a Web/Application server.
The MetadataProvider interface of Lightstreamer delegates the authentication to custom code, hence any scenario is totally feasible no matter how the current authentication cycle currently is. Anyway, in this article, we will focus on a rather common pattern where, upon authentication, the Web Server returns a token to the client (e.g.: through a cookie or through an ajax response) and the client uses that token every time it has to request data requiring an authenticated user to the same server. All in all, the user/password pair is only used once (well, the token will expire sooner or later, that's pretty obvious).
Instead of authenticating again the user, using the password within the Metadata Adapter, the suggested approach is to send the token received from the Web Server to Lightstreamer Server; in turn. the Metadata Adapter will validate the received token against the common back-end.
So, first thing, from the client, we grab user and password and we send them to the existing Web Server. In case of success we will have our token.
e.g.:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$.ajax({ | |
url: "login.js", | |
type: "POST", | |
data: { | |
user: user, | |
password: password, | |
}, | |
success: function(resp) { | |
token = resp; | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var lsClient = new LightstreamerClient(SERVER,ADAPTER); | |
lsClient.connectionDetails.setUser(user); | |
lsClient.connectionDetails.setPassword(token); | |
lsClient.connect(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public void notifyUser(String user, String token, Map httpHeaders) throws AccessException { | |
if (!AuthorizationRequest.isValidToken(user, token)) { | |
throw new AccessException("Invalid user/token"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
lsClient.addListener({ | |
onServerError:function(code,message) { | |
alert(message); | |
} | |
}); |
Authentication is now complete.
Authorization
Not all users are created equal though. Some will have access to certain items that others cannot see. The MetadataProvider also provides hooks where these kind of fine-grained authorization can be implemented and enforced.The MetadataProvider must first declare it wants to verify each and every subscription:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public boolean wantsTablesNotification(String user) { | |
return true; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var subscription = new Subscription(mode,itemList,fieldList); | |
subscription.setDataAdapter(dataAdapter); | |
lsClient.subscribe(subscription); |
As with user's authentication, in this example, the authorization policy is wrapped in a single method, namely canUserSeeItems. If the method fails to authorize the user against the items, a CreditsException has to be thrown to prevent the subscription from being fullfilled.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public void notifyNewTables(java.lang.String user, java.lang.String sessionID, TableInfo[] tables) throws CreditsException { | |
for (int i=0; i<tables.length; i++) { | |
String[] items = this.getItems(user, tables[i].getId()); | |
if (!AuthorizationRequest.canUserSeeItems(user, items)) { | |
throw new CreditsException(-1, "User not authorized", "You are not authorized to see this item"); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
subscription.addListener({ | |
onSubscription: function(updateInfo) { | |
//subscription successful! | |
}, | |
onSubscriptionError: function(code,message) { | |
//subscription refused | |
} | |
}); |
Examples
If you want to dig a little more on the topic, and start coding yourself, we suggest to explore the following projects:- Java Adapter:
https://github.com/Weswit/Lightstreamer-example-AuthMetadata-adapter-java - HTML Client:
https://github.com/Weswit/Lightstreamer-example-AuthMetadata-client-javascript
The live result can be seen here: http://demos.lightstreamer.com/AuthDemo/