Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
4295168
Added shirt dependencies
hayssams Apr 27, 2015
e52f4fb
default shiro configuration file
hayssams Apr 27, 2015
6e07f10
The connected or anonymous user should get a ticket first from this API
hayssams Apr 27, 2015
8178c2c
Shiro filter to protect access to the API.
hayssams Apr 27, 2015
774ada9
Very simple ticket container
hayssams Apr 27, 2015
c2b3cf3
User name & ticket are now required to access the notebook api since …
hayssams Apr 27, 2015
16f0ace
Notes are now loaded from and stored in a subdirectory named after th…
hayssams Apr 27, 2015
a8eb2cc
Web socket handlers require the username & ticket got through the ini…
hayssams Apr 27, 2015
f81aaa5
Notebooks are now user dependent. We still load all note in memory.
hayssams Apr 27, 2015
3f96384
Get ticket on startup
hayssams Apr 27, 2015
baf311c
Submit username & ticket on web socket requests
hayssams Apr 27, 2015
4c9167e
add user & ticket to API calls
hayssams Apr 27, 2015
f9244c3
Upgrade tests
hayssams Apr 27, 2015
ba1da14
Message hold the username & ticket now
hayssams Apr 27, 2015
7ab1b23
Angular objects are attached specific to a user
hayssams Apr 27, 2015
284e2ea
For an anonymous user, set ticket to anonymous to allow testing
hayssams Apr 27, 2015
cd05b62
Add missing import
hayssams Apr 27, 2015
5960221
Add Apache Licence
hayssams Apr 27, 2015
059b0fd
anonymous/anonymous is always a valid username/ticket combination
hayssams Apr 27, 2015
d4e513c
Merge branch 'master' into shira-security
hayssams May 7, 2015
aa4199e
Use HTTP Header for Auth
hayssams May 7, 2015
9c5316c
Remove reference to stormpath
hayssams May 7, 2015
6118b07
Merge with Zeppelin 26 #47
hayssams May 7, 2015
a471ded
Update Test
hayssams May 7, 2015
869663b
Handle correctly same user multiple devices refresh
hayssams May 7, 2015
18e26ee
Correct checktyle violation
hayssams May 7, 2015
97e6f8e
Make sure user folder exists before saving
hayssams May 7, 2015
167df71
disable auth in tests
hayssams May 7, 2015
b085537
Remove credentials from url in JUnit tests
hayssams May 7, 2015
7913fe6
Add auth Header to JUnit test
hayssams May 7, 2015
6cd9c9d
Display currently logged user name on main screen
hayssams May 7, 2015
80ca373
merge principal & ticket into a single header
hayssams May 8, 2015
4ceb507
Use principal from shiro context
hayssams May 8, 2015
1e66fdd
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Jun 6, 2015
4ae0f9a
Merge remote-tracking branch 'apache/master' into shira-security
hayssams Jul 11, 2015
c308d60
Merge branch 'master' into shira-security
hayssams Jul 12, 2015
5c36dc3
Apache licence
hayssams Jul 12, 2015
65a38e6
Merge branch 'master' into shira-security
hayssams Sep 20, 2015
2103a71
syntax error (missing tag)
hayssams Sep 20, 2015
b5c1e00
remove unused import
hayssams Sep 20, 2015
3d3498e
Make Notebook sync work with user specific notes
hayssams Sep 20, 2015
39066d1
make S3 work with user specific notes
hayssams Sep 20, 2015
c70f41c
use single quote in JS log message
hayssams Sep 20, 2015
5f0b496
minor code updates to cope with changes on upstream
hayssams Sep 25, 2015
401af7b
default shiro configuration file
hayssams Apr 27, 2015
aabe114
The connected or anonymous user should get a ticket first from this API
hayssams Apr 27, 2015
30e2d39
Shiro filter to protect access to the API.
hayssams Apr 27, 2015
e842e2e
Very simple ticket container
hayssams Apr 27, 2015
7114889
User name & ticket are now required to access the notebook api since …
hayssams Apr 27, 2015
b9d46ed
Revert to 6bc13e2
hayssams Sep 25, 2015
d9f06ba
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Sep 25, 2015
952cfeb
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Sep 27, 2015
df4ad07
what's root dir on travi-ci ?
hayssams Sep 27, 2015
290c17b
restore default note.
hayssams Sep 27, 2015
638b533
Move user notes to notebook/users folders
hayssams Sep 27, 2015
90f874f
Move user notes to notebook/users folders
hayssams Sep 27, 2015
e65e66c
remove socket registration in onOpen
hayssams Sep 27, 2015
9b4b809
minor code refactoring
hayssams Sep 27, 2015
0c8f9a9
start adding some Unit tests
hayssams Sep 28, 2015
011a85c
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Oct 4, 2015
e75a3cc
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Oct 8, 2015
42b37d1
Include Martin correction to the following bug : if you go from a not…
hayssams Oct 9, 2015
92e3ff0
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Oct 15, 2015
f2775c2
Include support in note creation api
hayssams Oct 19, 2015
de69dd3
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Oct 19, 2015
8792a93
Include users/anonymous directory in note path
hayssams Oct 19, 2015
3828f7b
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Oct 23, 2015
eb000be
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Nov 6, 2015
af16605
Added boolean property to prohibit anonymous access
hayssams Nov 20, 2015
4fc08b5
Handle property zeppelin.anonymous.allowed.
hayssams Nov 20, 2015
52ad68f
Merge branch 'master' of https://github.com/ebiznext/incubator-zeppel…
hayssams Nov 20, 2015
8856e79
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Nov 20, 2015
0c805ed
merge with master (add auth)
hayssams Nov 20, 2015
b2ed603
Update test to copy note in to users/[username] subdirectory
hayssams Nov 28, 2015
b7b53ec
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Dec 9, 2015
a45c578
dd auth support
hayssams Dec 9, 2015
c70d50f
remove extra conf
hayssams Dec 9, 2015
d5944e0
remove extra conf
hayssams Dec 9, 2015
d47d887
activate basic auth by default
hayssams Dec 10, 2015
3efc809
Anonymous access by default
hayssams Dec 14, 2015
117cba1
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Dec 14, 2015
a495ff9
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Dec 28, 2015
83deb10
fix security params
hayssams Dec 28, 2015
1402ef1
fix indentation
hayssams Dec 28, 2015
47b8f0b
More SecurityUtils
hayssams Dec 28, 2015
bb309f3
Added support for Lucene. On search only the notebooks of the connect…
hayssams Dec 29, 2015
29e0a52
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Dec 29, 2015
eb00798
Security readme
hayssams Dec 30, 2015
a39210e
Merge branch 'master' of https://github.com/apache/incubator-zeppelin…
hayssams Dec 30, 2015
3b27605
markdown fix
hayssams Dec 30, 2015
81488ea
minor update to import
hayssams Dec 31, 2015
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
63 changes: 63 additions & 0 deletions Security-README.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
# Vocabulary
username, owner and principal are used interchangeably to designate the currently authenticated user
# What are we securing ?
Zeppelin is basically a web application that spawn remote interpreters to run commands and return HTML fragments to be displayed on the user browser.
The scope of this PR is to secure the access to the notebooks. A user has access to his notebooks and only his notebooks. To achieve this, we use Apache Shiro.
## HTTP Endpoint security
Apache Shiro sits as a servlet filter between the browser and the exposed services and handles the required authentication without any programming required. (See Apache Shiro for more info).
## Websocket security
Securing the HTTP endpoints is not enough, since Zeppelin also communicates with the browser through websockets. To secure this channel, we take the following approach:
1. The browser on startup requests a ticket through HTTP
2. The Apache Shiro Servlet filter handles the user auth
3. Once the user is authenticated, a ticket is assigned to this user and the ticket is returned to the browser

All websockets communications require the username and ticket to be submitted by the browser. Upon receiving a websocket message, the server checks that the ticket received is the one assigned to the username through the HTTP request (step 3 above).

# Strategies to access the principal
Apache Shiro expose the principal through the following call

org.apache.shiro.SecurityUtils.getSubject().getPrincipal()

Apache Shiro stores the `principal` and the `subject` in a thread local variable.

That makes it possible to get the principal from wherever we need it in the application as long as we are in the context of a HTTP synchronous request.

Two strategies are possible : (1) Rely on the Thread local (anti ?)pattern to get the principal whenever we need it or (2) modify the interfaces of the NotebookRepo and SearchService classes to require the owner to be passed as a parameter.

## Relying on ThreadLocal
The Shiro ThreadLocal subject is available only for HTTP request which is not enough since we need to access notes through websockets (NotebookServer class) where the Shiro filter is not involved.

We could however explicitly create the Shiro `subject` on each websocket request using the provided username and ticket in the web socket request.

The drawback of this approach is that it makes it impossible to write async services and/or multithreaded code involving access to the Shiro principal (The subject is available in the current thread only).

On the other side, the main benefit of this approach is that it does not require any change to the NotebookRepo and the SearchService interfaces.

## Updating the service interfaces
Coming from an actor based concurrent & distributed programming background I have decided to go for this approach. This required me to add the owner parameter to a couple of method.

trait NotebookRepo {
...
public List<NoteInfo> list(String owner) throws IOException;
public Note get(String noteId, String owner) throws IOException;
...
}
trait SearchService {
public List<~> query(String queryStr, String owner);
}


As you can guess the has a significant impact on the existing code since the owner parameter had to be made available explicitly along the code that is executed to handle the request.

# How Notes are stored
TODO
# Future : How Permissions could be implemented (note sharing, accessible features in iframes …)
TODO





\`\`\`
\`
\`\`\`\`
13 changes: 13 additions & 0 deletions pom.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -208,6 +208,19 @@
<version>4.11</version>
<scope>test</scope>
</dependency>


<!-- Apache Shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -33,7 +33,7 @@
public class AngularObject<T> {
private String name;
private T object;

private String principal;
private transient AngularObjectListener listener;
private transient List<AngularObjectWatcher> watchers
= new LinkedList<AngularObjectWatcher>();
Expand DownExpand Up@@ -64,6 +64,14 @@ public boolean isGlobal() {
return noteId == null;
}

public String getPrincipal() {
return principal;
}

public void setPrincipal(String principal) {
this.principal = principal;
}

@Override
public boolean equals(Object o) {
if (o instanceof AngularObject) {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,7 +119,7 @@ public AngularObject remove(String name, String noteId, boolean emit) {
Map<String, AngularObject> r = getRegistryForKey(noteId);
AngularObject o = r.remove(name);
if (listener != null && emit) {
listener.onRemove(interpreterId, name, noteId);;
listener.onRemove(interpreterId, o);
}
return o;
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,5 +24,5 @@
public interface AngularObjectRegistryListener {
public void onAdd(String interpreterGroupId, AngularObject object);
public void onUpdate(String interpreterGroupId, AngularObject object);
public void onRemove(String interpreterGroupId, String name, String noteId);
public void onRemove(String interpreterGroupId, AngularObject object);
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -432,10 +432,10 @@ public void onUpdate(String interpreterGroupId, AngularObject object) {
}

@Override
public void onRemove(String interpreterGroupId, String name, String noteId) {
public void onRemove(String interpreterGroupId, AngularObject object) {
Map<String, String> removeObject = new HashMap<String, String>();
removeObject.put("name", name);
removeObject.put("noteId", noteId);
removeObject.put("name", object.getName());
removeObject.put("noteId", object.getNoteId());

sendEvent(new RemoteInterpreterEvent(
RemoteInterpreterEventType.ANGULAR_OBJECT_REMOVE, gson.toJson(removeObject)));
Expand DownExpand Up@@ -468,7 +468,6 @@ public RemoteInterpreterEvent getEvent() throws TException {

/**
* called when object is updated in client (web) side.
* @param className
* @param name
* @param noteId noteId where the update issues
* @param object
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,7 +45,7 @@ public void onUpdate(String interpreterGroupId, AngularObject object) {
}

@Override
public void onRemove(String interpreterGroupId, String name, String noteId) {
public void onRemove(String interpreterGroupId, AngularObject object) {
onRemove.incrementAndGet();
}
});
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -184,7 +184,7 @@ public void onUpdate(String interpreterGroupId, AngularObject object) {
}

@Override
public void onRemove(String interpreterGroupId, String name, String noteId) {
public void onRemove(String interpreterGroupId, AngularObject object) {
onRemove.incrementAndGet();
}

Expand Down
10 changes: 10 additions & 0 deletions zeppelin-server/pom.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -269,6 +269,16 @@
<version>1.9.0</version>
<scope>test</scope>
</dependency>

<!-- Apache Shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Loading