Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 0 additions & 6 deletions conf/zeppelin-site.xml.template
Original file line number Diff line number Diff line change
Expand Up @@ -426,12 +426,6 @@
<description>Allowed sources for REST and WebSocket requests (i.e. http://onehost:8080,http://otherhost.com). If you leave * you are vulnerable to https://issues.apache.org/jira/browse/ZEPPELIN-173</description>
</property>

<property>
<name>zeppelin.anonymous.allowed</name>
<value>true</value>
<description>Anonymous user allowed by default</description>
</property>

<property>
<name>zeppelin.username.force.lowercase</name>
<value>false</value>
Expand Down
6 changes: 0 additions & 6 deletions docs/setup/operation/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,6 @@ If both are defined, then the **environment variables** will take priority.
<td></td>
<td>If provided, encrypt passwords on the credentials.json file (passwords will be stored as plain-text otherwise</td>
</tr>
<tr>
<td>N/A</td>
<td><h6 class="properties">zeppelin.anonymous.allowed</h6></td>
<td>true</td>
<td>The anonymous user is allowed by default.</td>
</tr>
<tr>
<td><h6 class="properties">ZEPPELIN_SERVER_CONTEXT_PATH</h6></td>
<td><h6 class="properties">zeppelin.server.context.path</h6></td>
Expand Down
7 changes: 4 additions & 3 deletions docs/setup/operation/upgrading.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ So, copying `notebook` and `conf` directory should be enough.
- From 0.9, we change the notes file name structure ([ZEPPELIN-2619](https://issues.apache.org/jira/browse/ZEPPELIN-2619)) and move permissions info from `notebook-authorization.json` into note file itself [ZEPPELIN-3985](https://issues.apache.org/jira/browse/ZEPPELIN-3985). So when you upgrading zeppelin to 0.9, you need to upgrade note file. Here's steps you need to follow:
1. Backup your notes file in case the upgrade fails
2. Call `bin/upgrade-note.sh -d` to upgrade note, `-d` option means to delete the old note file, missing this option will keep the old file.
- From 0.9, Zeppelin server bind `127.0.0.1` by default instead of `0.0.0.0`. Configure `zeppelin.server.addr` property or `ZEPPELIN_ADDR` env variable to change.

- From 0.9, Zeppelin server bind `127.0.0.1` by default instead of `0.0.0.0`. Configure `zeppelin.server.addr` property or `ZEPPELIN_ADDR` env variable to change.
- From 0.9, we have removed `zeppelin.anonymous.allowed` ([ZEPPELIN-4489](https://issues.apache.org/jira/browse/ZEPPELIN-4489)). So, when you upgrade Zeppelin to 0.9 and if `shiro.ini` file does not exists in conf path then all the Zeppelin-Users runs as anonymous.

### Upgrading from Zeppelin 0.8.1 (and before) to 0.8.2 (and later)
- From 0.8.2, Zeppelin server bind `127.0.0.1` by default instead of `0.0.0.0`. Configure `zeppelin.server.addr` property or `ZEPPELIN_ADDR` env variable to change.
- From 0.8.2, Zeppelin server bind `127.0.0.1` by default instead of `0.0.0.0`. Configure `zeppelin.server.addr` property or `ZEPPELIN_ADDR` env variable to change.

### Upgrading from Zeppelin 0.7 to 0.8

Expand Down
7 changes: 2 additions & 5 deletions docs/setup/security/shiro_authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,15 @@ cp conf/shiro.ini.template conf/shiro.ini

For the further information about `shiro.ini` file format, please refer to [Shiro Configuration](http://shiro.apache.org/configuration.html#Configuration-INISections).

### 2. Secure the Websocket channel
Set to property **zeppelin.anonymous.allowed** to **false** in `conf/zeppelin-site.xml`. If you don't have this file yet, just copy `conf/zeppelin-site.xml.template` to `conf/zeppelin-site.xml`.

### 3. Start Zeppelin
### 2. Start Zeppelin

```bash
bin/zeppelin-daemon.sh start #(or restart)
```

Then you can browse Zeppelin at [http://localhost:8080](http://localhost:8080).

### 4. Login
### 3. Login
Finally, you can login using one of the below **username/password** combinations.

<center><img src="{{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/zeppelin-login.png"></center>
Expand Down
1 change: 0 additions & 1 deletion docs/usage/rest_api/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple
"zeppelin.notebook.homescreen": "",
"zeppelin.notebook.storage": "org.apache.zeppelin.notebook.repo.VFSNotebookRepo",
"zeppelin.interpreter.connect.timeout": "30000",
"zeppelin.anonymous.allowed": "true",
"zeppelin.server.allowed.origins":"*",
"zeppelin.encoding": "UTF-8"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.apache.zeppelin.conf;

import com.google.common.annotations.VisibleForTesting;
import java.io.File;
import java.io.IOException;
import java.net.URL;
Expand All @@ -25,8 +26,6 @@
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.configuration.tree.ConfigurationNode;
Expand All @@ -45,6 +44,8 @@ public class ZeppelinConfiguration extends XMLConfiguration {
private static final long serialVersionUID = 4749305895693848035L;
private static final Logger LOG = LoggerFactory.getLogger(ZeppelinConfiguration.class);

private Boolean anonymousAllowed;

private static final String HELIUM_PACKAGE_DEFAULT_URL =
"https://s3.amazonaws.com/helium-package/helium.json";
private static ZeppelinConfiguration conf;
Expand Down Expand Up @@ -566,7 +567,10 @@ public boolean isWindowsPath(String path){
}

public boolean isAnonymousAllowed() {
return getBoolean(ConfVars.ZEPPELIN_ANONYMOUS_ALLOWED);
if (anonymousAllowed == null) {
anonymousAllowed = this.getShiroPath().equals(StringUtils.EMPTY);
}
return anonymousAllowed;
}

public boolean isUsernameForceLowerCase() {
Expand Down Expand Up @@ -874,7 +878,6 @@ public enum ConfVars {
// Allows a way to specify a ',' separated list of allowed origins for rest and websockets
// i.e. http://localhost:8080
ZEPPELIN_ALLOWED_ORIGINS("zeppelin.server.allowed.origins", "*"),
ZEPPELIN_ANONYMOUS_ALLOWED("zeppelin.anonymous.allowed", true),
ZEPPELIN_USERNAME_FORCE_LOWERCASE("zeppelin.username.force.lowercase", false),
ZEPPELIN_CREDENTIALS_PERSIST("zeppelin.credentials.persist", true),
ZEPPELIN_CREDENTIALS_ENCRYPT_KEY("zeppelin.credentials.encryptKey", null),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,6 @@ private static void start(boolean withAuth,

if (withAuth) {
isRunningWithAuth = true;
// Set Anonymous session to false.
System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_ANONYMOUS_ALLOWED.getVarName(),
"false");

// Create a shiro env test.
shiroIni = new File(confDir, "shiro.ini");
Expand Down Expand Up @@ -321,9 +318,7 @@ protected static void shutDown(final boolean deleteConfDir) throws Exception {
LOG.info("Test Zeppelin terminated.");

if (isRunningWithAuth) {
isRunningWithAuth = false;
System
.clearProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_ANONYMOUS_ALLOWED.getVarName());
isRunningWithAuth = shiroIni.exists();
}

if (deleteConfDir && !TestUtils.getInstance(Notebook.class).getConf().isRecoveryEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,26 +112,6 @@ public void testThatWriterCannotRemoveNote() throws IOException {
assertNull("Deleted note should be null", deletedNote);
}

@Test
public void testThatUserCanSearchNote() throws IOException {
String noteId1 = createNoteForUser("test1", "admin", "password1");
createParagraphForUser(noteId1, "admin", "password1", "title1",
"ThisIsToTestSearchMethodWithPermissions 1");

String noteId2 = createNoteForUser("test2", "user1", "password2");
createParagraphForUser(noteId1, "admin", "password1", "title2",
"ThisIsToTestSearchMethodWithPermissions 2");

//set permission for each note
setPermissionForNote(noteId1, "admin", "password1");
setPermissionForNote(noteId1, "user1", "password2");

searchNoteBasedOnPermission("ThisIsToTestSearchMethodWithPermissions", "admin", "password1");

deleteNoteForUser(noteId1, "admin", "password1");
deleteNoteForUser(noteId2, "user1", "password2");
}

private void userTryRemoveNote(String noteId, String user, String pwd,
Matcher<? super HttpMethodBase> m) throws IOException {
DeleteMethod delete = httpDelete(("/notebook/" + noteId), user, pwd);
Expand Down Expand Up @@ -194,34 +174,4 @@ private void setPermissionForNote(String noteId, String user, String pwd) throws
PutMethod put = httpPut(("/notebook/" + noteId + "/permissions"), payload, user, pwd);
put.releaseConnection();
}

private void searchNoteBasedOnPermission(String searchText, String user, String pwd)
throws IOException{
GetMethod searchNote = httpGet(("/notebook/search?q=" + searchText), user, pwd);
Map<String, Object> respSearchResult = gson.fromJson(searchNote.getResponseBodyAsString(),
new TypeToken<Map<String, Object>>() {}.getType());
ArrayList searchBody = (ArrayList) respSearchResult.get("body");
assertEquals("At-least one search results is there", true, searchBody.size() >= 1);

for (int i = 0; i < searchBody.size(); i++) {
Map<String, String> searchResult = (Map<String, String>) searchBody.get(i);
String userId = searchResult.get("id").split("/", 2)[0];

GetMethod getPermission = httpGet(("/notebook/" + userId + "/permissions"), user, pwd);
Map<String, Object> resp = gson.fromJson(getPermission.getResponseBodyAsString(),
new TypeToken<Map<String, Object>>() {}.getType());
Map<String, ArrayList> permissions = (Map<String, ArrayList>) resp.get("body");
ArrayList owners = permissions.get("owners");
ArrayList readers = permissions.get("readers");
ArrayList writers = permissions.get("writers");
ArrayList runners = permissions.get("runners");

if (owners.size() != 0 && readers.size() != 0 && writers.size() != 0 && runners.size() != 0) {
assertEquals("User has permissions ", true, (owners.contains(user) ||
readers.contains(user) || writers.contains(user) || runners.contains(user)));
}
getPermission.releaseConnection();
}
searchNote.releaseConnection();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public void init(ZeppelinConfiguration conf) throws IOException {
}

// sync for anonymous mode on start
if (getRepoCount() > 1 && conf.getBoolean(ConfVars.ZEPPELIN_ANONYMOUS_ALLOWED)) {
if (getRepoCount() > 1 && conf.isAnonymousAllowed()) {
try {
sync(AuthenticationInfo.ANONYMOUS);
} catch (IOException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ public class Authentication implements Runnable {
private static final String CIPHER_MODE = "AES/CBC/PKCS5PADDING";
private static final int ivSize = 16;

private static final String ZEPPELIN_CONF_ANONYMOUS_ALLOWED = "zeppelin.anonymous.allowed";
private static final String ZEPPELINHUB_USER_KEY = "zeppelinhub.user.key";
private String token;
private boolean authEnabled;
Expand All @@ -75,8 +74,7 @@ private Authentication(String token, ZeppelinConfiguration conf) {
client = new HttpClient(connectionManager);
this.token = token;

authEnabled = !conf.getBoolean("ZEPPELIN_ALLOW_ANONYMOUS",
ZEPPELIN_CONF_ANONYMOUS_ALLOWED, true);
authEnabled = !conf.isAnonymousAllowed();

userKey = conf.getString("ZEPPELINHUB_USER_KEY",
ZEPPELINHUB_USER_KEY, "");
Expand Down