Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ZEPPELIN-6075] Configuration for global Roles #4808

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
30 changes: 30 additions & 0 deletions docs/setup/operation/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,36 @@ Sources descending by priority:
<td>true</td>
<td>Value to enable/disable version control support in Notes.</td>
</tr>
<tr>
<td><h6 class="properties">ZEPPELIN_OWNER_ROLE</h6></td>
<td><h6 class="properties">zeppelin.notebook.default.owner.username</h6></td>
<td></td>
<td>Username of the Zeppelin Note Administrator</td>
</tr>
<tr>
<td><h6 class="properties">ZEPPELIN_OWNER_ROLES</h6></td>
<td><h6 class="properties">zeppelin.notebook.default.owners</h6></td>
<td></td>
<td>Comma-separated list of global note owners, which are de facto note administrators.</td>
</tr>
<tr>
<td><h6 class="properties">ZEPPELIN_WRITER_ROLES</h6></td>
<td><h6 class="properties">zeppelin.notebook.default.writers</h6></td>
<td></td>
<td>Comma-separated list of global note writers.</td>
</tr>
<tr>
<td><h6 class="properties">ZEPPELIN_RUNNER_ROLES</h6></td>
<td><h6 class="properties">zeppelin.notebook.default.runners</h6></td>
<td></td>
<td>Comma-separated list of global note runners.</td>
</tr>
<tr>
<td><h6 class="properties">ZEPPELIN_READER_ROLES</h6></td>
<td><h6 class="properties">zeppelin.notebook.default.readers</h6></td>
<td></td>
<td>Comma-separated list of global note readers.</td>
</tr>
</table>


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,10 @@ public enum ConfVars {
ZEPPELIN_INTERPRETER_SCHEDULER_POOL_SIZE("zeppelin.scheduler.threadpool.size", 100),

ZEPPELIN_OWNER_ROLE("zeppelin.notebook.default.owner.username", ""),
ZEPPELIN_OWNER_ROLES("zeppelin.notebook.default.owners", ""),
ZEPPELIN_WRITER_ROLES("zeppelin.notebook.default.writers", ""),
ZEPPELIN_READER_ROLES("zeppelin.notebook.default.readers", ""),
ZEPPELIN_RUNNER_ROLES("zeppelin.notebook.default.runners", ""),

ZEPPELIN_RUN_MODE("zeppelin.run.mode", "auto"), // auto | local | k8s | Docker

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

import javax.inject.Inject;
import java.io.IOException;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
Expand All @@ -43,6 +45,12 @@ public class AuthorizationService {
private final ZeppelinConfiguration zConf;
private final ConfigStorage configStorage;

private static final Set<ZeppelinConfiguration.ConfVars> VALID_ROLES_CONF_VARS = EnumSet.of(
ZeppelinConfiguration.ConfVars.ZEPPELIN_OWNER_ROLES,
ZeppelinConfiguration.ConfVars.ZEPPELIN_WRITER_ROLES,
ZeppelinConfiguration.ConfVars.ZEPPELIN_READER_ROLES,
ZeppelinConfiguration.ConfVars.ZEPPELIN_RUNNER_ROLES);

// contains roles for each user (username --> roles)
private Map<String, Set<String>> userRoles = new ConcurrentHashMap<>();

Expand Down Expand Up @@ -106,8 +114,9 @@ public void removeNoteAuth(String noteId) {
private Set<String> normalizeUsers(Set<String> users) {
Set<String> returnUser = new HashSet<>();
for (String user : users) {
if (!user.trim().isEmpty()) {
returnUser.add(user.trim());
String trimmedUser = user.trim();
if (!trimmedUser.isEmpty()) {
returnUser.add(trimmedUser);
}
}
return returnUser;
Expand Down Expand Up @@ -235,28 +244,67 @@ public Set<String> getRoles(String user) {
}

public boolean isOwner(String noteId, Set<String> entities) {
return isMember(entities, getOwners(noteId)) || isAdmin(entities);
return isMember(entities, constructRoles(getOwners(noteId), getDefaultOwners())) ||
isAdmin(entities);
}

public boolean isWriter(String noteId, Set<String> entities) {
return isMember(entities, getWriters(noteId)) ||
isMember(entities, getOwners(noteId)) ||
isAdmin(entities);
return isMember(entities, constructRoles(getWriters(noteId), getDefaultWriters())) ||
isMember(entities, constructRoles(getOwners(noteId), getDefaultOwners())) ||
isAdmin(entities);
}

public boolean isReader(String noteId, Set<String> entities) {
return isMember(entities, getReaders(noteId)) ||
isMember(entities, getOwners(noteId)) ||
isMember(entities, getWriters(noteId)) ||
isMember(entities, getRunners(noteId)) ||
isAdmin(entities);
return isMember(entities, constructRoles(getReaders(noteId), getDefaultReaders())) ||
isMember(entities, constructRoles(getOwners(noteId), getDefaultOwners())) ||
isMember(entities, constructRoles(getWriters(noteId), getDefaultWriters())) ||
isMember(entities, constructRoles(getRunners(noteId), getDefaultRunners())) ||
isAdmin(entities);
}

public boolean isRunner(String noteId, Set<String> entities) {
return isMember(entities, getRunners(noteId)) ||
isMember(entities, getWriters(noteId)) ||
isMember(entities, getOwners(noteId)) ||
isAdmin(entities);
return isMember(entities, constructRoles(getRunners(noteId), getDefaultRunners())) ||
isMember(entities, constructRoles(getWriters(noteId), getDefaultWriters())) ||
isMember(entities, constructRoles(getOwners(noteId), getDefaultOwners())) ||
isAdmin(entities);
}

private Set<String> constructRoles(Set<String> noteRoles, Set<String> globalRoles) {
Set<String> roles = new HashSet<>(noteRoles);
// If the note has no role, the note right is for everyone, so we are not allowed to add the default roles
if (!roles.isEmpty()) {
roles.addAll(globalRoles);
}
return roles;
}

private Set<String> getDefaultOwners() {
return getDefaultRoles(ZeppelinConfiguration.ConfVars.ZEPPELIN_OWNER_ROLES);
}

private Set<String> getDefaultWriters() {
return getDefaultRoles(ZeppelinConfiguration.ConfVars.ZEPPELIN_WRITER_ROLES);
}

private Set<String> getDefaultReaders() {
return getDefaultRoles(ZeppelinConfiguration.ConfVars.ZEPPELIN_READER_ROLES);
}

private Set<String> getDefaultRunners() {
return getDefaultRoles(ZeppelinConfiguration.ConfVars.ZEPPELIN_RUNNER_ROLES);
}

private Set<String> getDefaultRoles(ZeppelinConfiguration.ConfVars confvar) {
if (!VALID_ROLES_CONF_VARS.contains(confvar)) {
LOGGER.warn("getDefaultRoles is used with {}, which is not valid", confvar);
return Collections.emptySet();
}
Set<String> defaultRoles = new HashSet<>();
String defaultRolesConf = zConf.getString(confvar);
if (StringUtils.isNotBlank(defaultRolesConf)) {
Collections.addAll(defaultRoles, StringUtils.split(defaultRolesConf, ','));
}
return normalizeUsers(defaultRoles);
}

private boolean isAdmin(Set<String> entities) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.zeppelin.storage;

import java.io.IOException;

import org.apache.zeppelin.conf.ZeppelinConfiguration;
import org.apache.zeppelin.interpreter.InterpreterInfoSaving;
import org.apache.zeppelin.notebook.NotebookAuthorizationInfoSaving;

/**
* Storing config in memory
* This class is primarily for test cases
*/
public class InMemoryConfigStorage extends ConfigStorage {

private InterpreterInfoSaving settingInfos;
private NotebookAuthorizationInfoSaving authorizationInfoSaving;
private String credentials;

public InMemoryConfigStorage(ZeppelinConfiguration zConf) {
super(zConf);
}

@Override
public void save(InterpreterInfoSaving settingInfos) throws IOException {
this.settingInfos = settingInfos;
}

@Override
public InterpreterInfoSaving loadInterpreterSettings() throws IOException {
return settingInfos;
}

@Override
public void save(NotebookAuthorizationInfoSaving authorizationInfoSaving) throws IOException {
this.authorizationInfoSaving = authorizationInfoSaving;
}

@Override
public NotebookAuthorizationInfoSaving loadNotebookAuthorization() throws IOException {
return authorizationInfoSaving;
}

@Override
public String loadCredentials() throws IOException {
return credentials;
}

@Override
public void saveCredentials(String credentials) throws IOException {
this.credentials = credentials;
}

}
Loading
Loading