Skip to content

Commit

Permalink
The Websocket channel is now as secure as the HTTP channel.
Browse files Browse the repository at this point in the history
  • Loading branch information
hayssams committed Dec 31, 2015
1 parent e2affca commit f9b1952
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ public static enum OP {

public OP op;
public Map<String, Object> data = new HashMap<String, Object>();
public String ticket;
public String principal;

public Message(OP op) {
this.op = op;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.apache.zeppelin.scheduler.JobListener;
import org.apache.zeppelin.server.ZeppelinServer;
import org.apache.zeppelin.socket.Message.OP;
import org.apache.zeppelin.ticket.TicketContainer;
import org.apache.zeppelin.utils.SecurityUtils;
import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.WebSocketServlet;
Expand Down Expand Up @@ -96,6 +97,19 @@ public void onMessage(NotebookSocket conn, String msg) {
try {
Message messagereceived = deserializeMessage(msg);
LOG.debug("RECEIVE << " + messagereceived.op);
LOG.debug("RECEIVE PRINCIPAL << " + messagereceived.principal);
LOG.debug("RECEIVE TICKET << " + messagereceived.ticket);
String ticket = TicketContainer.instance.getTicket(messagereceived.principal);
if (ticket != null && !ticket.equals(messagereceived.ticket))
throw new Exception("Invalid ticket " + messagereceived.ticket + " != " + ticket);

ZeppelinConfiguration conf = ZeppelinConfiguration.create();
boolean allowAnonymous = conf.
getBoolean(ZeppelinConfiguration.ConfVars.ZEPPELIN_ANONYMOUS_ALLOWED);
if (!allowAnonymous && messagereceived.principal.equals("anonymous")) {
throw new Exception("Anonymous access not allowed ");
}

/** Lets be elegant here */
switch (messagereceived.op) {
case LIST_NOTES:
Expand Down
8 changes: 7 additions & 1 deletion zeppelin-web/src/app/home/home.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@
'use strict';

angular.module('zeppelinWebApp').controller('HomeCtrl', function($scope, notebookListDataFactory, websocketMsgSrv, $rootScope, arrayOrderingSrv) {

if (!$rootScope.ticket) {
$rootScope.ticket = {
'principal':'anonymous',
'ticket':'anonymous'
};
}

var vm = this;
vm.notes = notebookListDataFactory;
vm.websocketMsgSrv = websocketMsgSrv;
Expand Down
32 changes: 30 additions & 2 deletions zeppelin-web/src/components/navbar/navbar.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,22 @@
'use strict';

angular.module('zeppelinWebApp').controller('NavCtrl', function($scope, $rootScope, $routeParams,
$location, notebookListDataFactory, websocketMsgSrv, arrayOrderingSrv) {
$location, notebookListDataFactory, websocketMsgSrv, arrayOrderingSrv, $http) {
if (!$rootScope.ticket) {
$rootScope.ticket = {
'principal':'anonymous',
'ticket':'anonymous'
};
}

/** Current list of notes (ids) */

var vm = this;
vm.notes = notebookListDataFactory;
vm.connected = websocketMsgSrv.isConnected();
vm.websocketMsgSrv = websocketMsgSrv;
vm.arrayOrderingSrv = arrayOrderingSrv;
vm.authenticated = $rootScope.ticket.principal !== 'anonymous';

angular.element('#notebook-list').perfectScrollbar({suppressScrollX: true});

Expand Down Expand Up @@ -51,7 +59,27 @@ angular.module('zeppelinWebApp').controller('NavCtrl', function($scope, $rootSco
websocketMsgSrv.getNotebookList();
}

function isActive(noteId) {
/** ask for a ticket for websocket access
* Shiro will require credentials here
* */
$http.get('/api/security/ticket').
success(function(ticket, status, headers, config) {
if (status === 401 || status === 403) {
// Dislay error message here
}
else {
$rootScope.ticket = angular.fromJson(ticket).body;
vm.loadNotes = loadNotes;
vm.isActive = isActive;
vm.loadNotes();
vm.authenticated = $rootScope.ticket.principal !== 'anonymous';
}
}).
error(function(data, status, headers, config) {
console.log('Could not get ticket');
});

function isActive(noteId) {
return ($routeParams.noteId === noteId);
}

Expand Down
4 changes: 2 additions & 2 deletions zeppelin-web/src/components/navbar/navbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@
</li>
<li class="server-status">
<i class="fa fa-circle" ng-class="{'server-connected':navbar.connected, 'server-disconnected':!navbar.connected}"></i>
<span ng-show="navbar.connected">Connected</span>
<span ng-show="!navbar.connected">Disconnected</span>
<span ng-show="navbar.authenticated">{{ticket.principal}} connected</span>
<span ng-show="!navbar.authenticated">Disconnected</span>
</li>
</ul>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ angular.module('zeppelinWebApp').factory('websocketEvents', function($rootScope,
});

websocketCalls.sendNewEvent = function(data) {
console.log('Send >> %o, %o', data.op, data);
data.principal = $rootScope.ticket.principal;
data.ticket = $rootScope.ticket.ticket;
console.log('Send >> %o, %o, %o, %o', data.op, data.principal, data.ticket, data);
websocketCalls.ws.send(JSON.stringify(data));
};

Expand Down

0 comments on commit f9b1952

Please sign in to comment.