settingIds =
- notebook.getInterpreterSettingManager().getInterpreters(note.getId());
+ notebook.getInterpreterSettingManager().getInterpreterBinding(note.getId());
for (String id : settingIds) {
if (interpreterGroupId.contains(id)) {
broadcast(note.getId(),
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/utils/AnyOfRolesAuthorizationFilter.java b/zeppelin-server/src/main/java/org/apache/zeppelin/utils/AnyOfRolesAuthorizationFilter.java
new file mode 100644
index 0000000000..37c91466b3
--- /dev/null
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/utils/AnyOfRolesAuthorizationFilter.java
@@ -0,0 +1,53 @@
+/*
+ * 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.utils;
+
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import java.io.IOException;
+
+/**
+ * Allows access if current user has at least one role of the specified list.
+ *
+ * Basically, it's the same as {@link RolesAuthorizationFilter} but using {@literal OR} instead
+ * of {@literal AND} on the specified roles.
+ */
+public class AnyOfRolesAuthorizationFilter extends RolesAuthorizationFilter {
+
+ @Override
+ public boolean isAccessAllowed(ServletRequest request, ServletResponse response,
+ Object mappedValue) throws IOException {
+
+ final Subject subject = getSubject(request, response);
+ final String[] rolesArray = (String[]) mappedValue;
+
+ if (rolesArray == null || rolesArray.length == 0) {
+ //no roles specified, so nothing to check - allow access.
+ return true;
+ }
+
+ for (String roleName : rolesArray) {
+ if (subject.hasRole(roleName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java b/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java
index b2029ecf6f..983166b61a 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java
@@ -20,16 +20,21 @@ import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
+import java.security.Principal;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
+import javax.naming.NamingException;
+
+import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.IniRealm;
+import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
@@ -88,13 +93,24 @@ public class SecurityUtils {
String principal;
if (subject.isAuthenticated()) {
- principal = subject.getPrincipal().toString();
+ principal = extractPrincipal(subject);
} else {
principal = ANONYMOUS;
}
return principal;
}
+ private static String extractPrincipal(Subject subject) {
+ String principal;
+ Object principalObject = subject.getPrincipal();
+ if (principalObject instanceof Principal) {
+ principal = ((Principal) principalObject).getName();
+ } else {
+ principal = String.valueOf(principalObject);
+ }
+ return principal;
+ }
+
public static Collection getRealmsList() {
if (!isEnabled) {
return Collections.emptyList();
@@ -129,7 +145,15 @@ public class SecurityUtils {
allRoles = ((IniRealm) realm).getIni().get("roles");
break;
} else if (name.equals("org.apache.zeppelin.realm.LdapRealm")) {
- allRoles = ((LdapRealm) realm).getListRoles();
+ try {
+ AuthorizationInfo auth = ((LdapRealm) realm).queryForAuthorizationInfo(
+ new SimplePrincipalCollection(subject.getPrincipal(), realm.getName()),
+ ((LdapRealm) realm).getContextFactory()
+ );
+ roles = new HashSet<>(auth.getRoles());
+ } catch (NamingException e) {
+ log.error("Can't fetch roles", e);
+ }
break;
} else if (name.equals("org.apache.zeppelin.realm.ActiveDirectoryGroupRealm")) {
allRoles = ((ActiveDirectoryGroupRealm) realm).getListRoles();
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java b/zeppelin-server/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
index 475be50270..6f537fd80c 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
@@ -40,6 +40,7 @@ abstract public class AbstractZeppelinIT {
protected static WebDriver driver;
protected final static Logger LOG = LoggerFactory.getLogger(AbstractZeppelinIT.class);
+ protected static final long MIN_IMPLICIT_WAIT = 5;
protected static final long MAX_IMPLICIT_WAIT = 30;
protected static final long MAX_BROWSER_TIMEOUT_SEC = 30;
protected static final long MAX_PARAGRAPH_TIMEOUT_SEC = 120;
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/WebDriverManager.java b/zeppelin-server/src/test/java/org/apache/zeppelin/WebDriverManager.java
index da34e7299a..82dc9cc16d 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/WebDriverManager.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/WebDriverManager.java
@@ -81,8 +81,9 @@ public class WebDriverManager {
profile.setPreference("browser.helperApps.neverAsk.saveToDisk", "application/x-ustar,application/octet-stream,application/zip,text/csv,text/plain");
profile.setPreference("network.proxy.type", 0);
- profile.addExtension(new File(firebugPath));
- profile.addExtension(new File(firepathPath));
+ // Commenting out installing extensions. See ZEPPELIN-2962.
+ // profile.addExtension(new File(firebugPath));
+ // profile.addExtension(new File(firepathPath));
driver = new FirefoxDriver(ffox, profile);
} catch (Exception e) {
@@ -141,6 +142,7 @@ public class WebDriverManager {
fail();
}
+ driver.manage().window().maximize();
return driver;
}
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java
index f87bff2ce5..3d1406aebc 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java
@@ -23,7 +23,6 @@ import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
-
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.zeppelin.AbstractZeppelinIT;
@@ -38,6 +37,7 @@ import org.junit.Test;
import org.junit.rules.ErrorCollector;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
+import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,12 +63,14 @@ public class AuthenticationIT extends AbstractZeppelinIT {
"securityManager.sessionManager = $sessionManager\n" +
"securityManager.sessionManager.globalSessionTimeout = 86400000\n" +
"shiro.loginUrl = /api/login\n" +
+ "anyofroles = org.apache.zeppelin.utils.AnyOfRolesAuthorizationFilter\n" +
"[roles]\n" +
"admin = *\n" +
"hr = *\n" +
"finance = *\n" +
"[urls]\n" +
"/api/version = anon\n" +
+ "/api/interpreter/** = authc, anyofroles[admin, finance]\n" +
"/** = authc";
static String originalShiro = "";
@@ -81,7 +83,7 @@ public class AuthenticationIT extends AbstractZeppelinIT {
}
try {
- System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_HOME.getVarName(), "../");
+ System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_HOME.getVarName(), new File("../").getAbsolutePath());
ZeppelinConfiguration conf = ZeppelinConfiguration.create();
shiroPath = conf.getRelativeDir(String.format("%s/shiro.ini", conf.getConfDir()));
File file = new File(shiroPath);
@@ -182,6 +184,62 @@ public class AuthenticationIT extends AbstractZeppelinIT {
}
}
+ @Test
+ public void testAnyOfRoles() throws Exception {
+ if (!endToEndTestEnabled()) {
+ return;
+ }
+ try {
+ AuthenticationIT authenticationIT = new AuthenticationIT();
+ authenticationIT.authenticationUser("admin", "password1");
+
+ pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"),
+ MAX_BROWSER_TIMEOUT_SEC).click();
+ clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]"));
+
+ collector.checkThat("Check is user has permission to view this page", true,
+ CoreMatchers.equalTo(pollingWait(By.xpath(
+ "//div[@id='main']/div/div[2]"),
+ MIN_IMPLICIT_WAIT).isDisplayed())
+ );
+
+ authenticationIT.logoutUser("admin");
+
+ authenticationIT.authenticationUser("finance1", "finance1");
+
+ pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"),
+ MAX_BROWSER_TIMEOUT_SEC).click();
+ clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]"));
+
+ collector.checkThat("Check is user has permission to view this page", true,
+ CoreMatchers.equalTo(pollingWait(By.xpath(
+ "//div[@id='main']/div/div[2]"),
+ MIN_IMPLICIT_WAIT).isDisplayed())
+ );
+
+ authenticationIT.logoutUser("finance1");
+
+ authenticationIT.authenticationUser("hr1", "hr1");
+
+ pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"),
+ MAX_BROWSER_TIMEOUT_SEC).click();
+ clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]"));
+
+ try {
+ collector.checkThat("Check is user has permission to view this page",
+ true, CoreMatchers.equalTo(
+ pollingWait(By.xpath("//li[contains(@class, 'ng-toast__message')]//span/span"),
+ MIN_IMPLICIT_WAIT).isDisplayed()));
+ } catch (TimeoutException e) {
+ throw new Exception("Expected ngToast not found", e);
+ }
+ authenticationIT.logoutUser("hr1");
+
+ } catch (Exception e) {
+ handleException("Exception in AuthenticationIT while testAnyOfRoles ", e);
+ }
+ }
+
@Test
public void testGroupPermission() throws Exception {
if (!endToEndTestEnabled()) {
@@ -200,6 +258,8 @@ public class AuthenticationIT extends AbstractZeppelinIT {
MAX_BROWSER_TIMEOUT_SEC).sendKeys("finance ");
pollingWait(By.xpath(".//*[@id='selectReaders']/following::span//input"),
MAX_BROWSER_TIMEOUT_SEC).sendKeys("finance ");
+ pollingWait(By.xpath(".//*[@id='selectRunners']/following::span//input"),
+ MAX_BROWSER_TIMEOUT_SEC).sendKeys("finance ");
pollingWait(By.xpath(".//*[@id='selectWriters']/following::span//input"),
MAX_BROWSER_TIMEOUT_SEC).sendKeys("finance ");
pollingWait(By.xpath("//button[@ng-click='savePermissions()']"), MAX_BROWSER_TIMEOUT_SEC)
@@ -254,7 +314,7 @@ public class AuthenticationIT extends AbstractZeppelinIT {
} catch (Exception e) {
- handleException("Exception in ParagraphActionsIT while testGroupPermission ", e);
+ handleException("Exception in AuthenticationIT while testGroupPermission ", e);
}
}
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java
index 9bfeae0184..999e796192 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java
@@ -72,7 +72,7 @@ public class InterpreterModeActionsIT extends AbstractZeppelinIT {
static String interpreterOptionPath = "";
static String originalInterpreterOption = "";
- static String cmdPsPython = "ps aux | grep 'zeppelin_python-' | grep -v 'grep' | wc -l";
+ static String cmdPsPython = "ps aux | grep 'zeppelin_ipython' | grep -v 'grep' | wc -l";
static String cmdPsInterpreter = "ps aux | grep 'zeppelin/interpreter/python/*' |" +
" sed -E '/grep|local-repo/d' | wc -l";
@@ -82,7 +82,7 @@ public class InterpreterModeActionsIT extends AbstractZeppelinIT {
return;
}
try {
- System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_HOME.getVarName(), "../");
+ System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_HOME.getVarName(), new File("../").getAbsolutePath());
ZeppelinConfiguration conf = ZeppelinConfiguration.create();
shiroPath = conf.getRelativeDir(String.format("%s/shiro.ini", conf.getConfDir()));
interpreterOptionPath = conf.getRelativeDir(String.format("%s/interpreter.json", conf.getConfDir()));
@@ -145,19 +145,19 @@ public class InterpreterModeActionsIT extends AbstractZeppelinIT {
}
private void logoutUser(String userName) throws URISyntaxException {
- pollingWait(By.xpath("//div[contains(@class, 'navbar-collapse')]//li[contains(.,'" +
- userName + "')]"), MAX_BROWSER_TIMEOUT_SEC).click();
- pollingWait(By.xpath("//div[contains(@class, 'navbar-collapse')]//li[contains(.,'" +
- userName + "')]//a[@ng-click='navbar.logout()']"), MAX_BROWSER_TIMEOUT_SEC).click();
-
- By locator = By.xpath("//*[@id='loginModal']//div[contains(@class, 'modal-header')]/button");
- WebElement element = (new WebDriverWait(driver, MAX_BROWSER_TIMEOUT_SEC))
- .until(ExpectedConditions.visibilityOfElementLocated(locator));
- if (element.isDisplayed()) {
+ ZeppelinITUtils.sleep(500, false);
+ driver.findElement(By.xpath("//div[contains(@class, 'navbar-collapse')]//li[contains(.,'" +
+ userName + "')]")).click();
+ ZeppelinITUtils.sleep(500, false);
+ driver.findElement(By.xpath("//div[contains(@class, 'navbar-collapse')]//li[contains(.,'" +
+ userName + "')]//a[@ng-click='navbar.logout()']")).click();
+ ZeppelinITUtils.sleep(2000, false);
+ if (driver.findElement(By.xpath("//*[@id='loginModal']//div[contains(@class, 'modal-header')]/button"))
+ .isDisplayed()) {
driver.findElement(By.xpath("//*[@id='loginModal']//div[contains(@class, 'modal-header')]/button")).click();
}
driver.get(new URI(driver.getCurrentUrl()).resolve("/#/").toString());
- ZeppelinITUtils.sleep(1000, false);
+ ZeppelinITUtils.sleep(500, false);
}
private void setPythonParagraph(int num, String text) {
@@ -199,7 +199,6 @@ public class InterpreterModeActionsIT extends AbstractZeppelinIT {
"//div[@class='modal-dialog']//div[@class='bootstrap-dialog-footer-buttons']//button[contains(., 'OK')]"));
clickAndWait(By.xpath("//a[@class='navbar-brand navbar-title'][contains(@href, '#/')]"));
interpreterModeActionsIT.logoutUser("admin");
-
//step 2: (user1) login, create a new note, run two paragraph with 'python', check result, check process, logout
//paragraph: Check if the result is 'user1' in the second paragraph
//System: Check if the number of python interpreter process is '1'
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/PersonalizeActionsIT.java b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/PersonalizeActionsIT.java
index b813ea9ec4..dc07435865 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/PersonalizeActionsIT.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/PersonalizeActionsIT.java
@@ -74,7 +74,7 @@ public class PersonalizeActionsIT extends AbstractZeppelinIT {
return;
}
try {
- System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_HOME.getVarName(), "../");
+ System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_HOME.getVarName(), new File("../").getAbsolutePath());
ZeppelinConfiguration conf = ZeppelinConfiguration.create();
shiroPath = conf.getRelativeDir(String.format("%s/shiro.ini", conf.getConfDir()));
File file = new File(shiroPath);
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/SparkParagraphIT.java b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/SparkParagraphIT.java
index 9b651c1f16..8afdb9bff9 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/SparkParagraphIT.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/SparkParagraphIT.java
@@ -138,7 +138,7 @@ public class SparkParagraphIT extends AbstractZeppelinIT {
WebElement paragraph1Result = driver.findElement(By.xpath(
getParagraphXPath(1) + "//div[contains(@id,\"_text\")]"));
collector.checkThat("Paragraph from SparkParagraphIT of testPySpark result: ",
- paragraph1Result.getText().toString(), CoreMatchers.equalTo("test loop 0\ntest loop 1\ntest loop 2")
+ paragraph1Result.getText().toString(), CoreMatchers.containsString("test loop 0\ntest loop 1\ntest loop 2")
);
// the last statement's evaluation result is printed
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/realm/LdapRealmTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/realm/LdapRealmTest.java
new file mode 100644
index 0000000000..9070c5f4e3
--- /dev/null
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/realm/LdapRealmTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.realm;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapContext;
+
+import org.apache.shiro.realm.ldap.LdapContextFactory;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.subject.SimplePrincipalCollection;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+
+public class LdapRealmTest {
+
+ @Test
+ public void testGetUserDn() {
+ LdapRealm realm = new LdapRealm();
+
+ // without a user search filter
+ realm.setUserSearchFilter(null);
+ assertEquals(
+ "foo ",
+ realm.getUserDn("foo ")
+ );
+
+ // with a user search filter
+ realm.setUserSearchFilter("memberUid={0}");
+ assertEquals(
+ "foo",
+ realm.getUserDn("foo")
+ );
+ }
+
+ @Test
+ public void testExpandTemplate() {
+ assertEquals(
+ "uid=foo,cn=users,dc=ods,dc=foo",
+ LdapRealm.expandTemplate("uid={0},cn=users,dc=ods,dc=foo", "foo")
+ );
+ }
+
+ @Test
+ public void getUserDnForSearch() {
+ LdapRealm realm = new LdapRealm();
+
+ realm.setUserSearchAttributeName("uid");
+ assertEquals(
+ "foo",
+ realm.getUserDnForSearch("foo")
+ );
+
+ // using a template
+ realm.setUserSearchAttributeName(null);
+ realm.setMemberAttributeValueTemplate("cn={0},ou=people,dc=hadoop,dc=apache");
+ assertEquals(
+ "cn=foo,ou=people,dc=hadoop,dc=apache",
+ realm.getUserDnForSearch("foo")
+ );
+ }
+
+ @Test
+ public void testRolesFor() throws NamingException {
+ LdapRealm realm = new LdapRealm();
+ realm.setGroupSearchBase("cn=groups,dc=apache");
+ realm.setGroupObjectClass("posixGroup");
+ realm.setMemberAttributeValueTemplate("cn={0},ou=people,dc=apache");
+ HashMap rolesByGroups = new HashMap<>();
+ rolesByGroups.put("group-three", "zeppelin-role");
+ realm.setRolesByGroup(rolesByGroups);
+
+ LdapContextFactory ldapContextFactory = mock(LdapContextFactory.class);
+ LdapContext ldapCtx = mock(LdapContext.class);
+ Session session = mock(Session.class);
+
+
+ // expected search results
+ BasicAttributes group1 = new BasicAttributes();
+ group1.put(realm.getGroupIdAttribute(), "group-one");
+ group1.put(realm.getMemberAttribute(), "principal");
+
+ // user doesn't belong to this group
+ BasicAttributes group2 = new BasicAttributes();
+ group2.put(realm.getGroupIdAttribute(), "group-two");
+ group2.put(realm.getMemberAttribute(), "someoneelse");
+
+ // mapped to a different Zeppelin role
+ BasicAttributes group3 = new BasicAttributes();
+ group3.put(realm.getGroupIdAttribute(), "group-three");
+ group3.put(realm.getMemberAttribute(), "principal");
+
+ NamingEnumeration results = enumerationOf(group1, group2, group3);
+ when(ldapCtx.search(any(String.class), any(String.class), any(SearchControls.class))).thenReturn(results);
+
+
+ Set roles = realm.rolesFor(
+ new SimplePrincipalCollection("principal", "ldapRealm"),
+ "principal",
+ ldapCtx,
+ ldapContextFactory,
+ session
+ );
+
+ verify(ldapCtx).search(
+ "cn=groups,dc=apache",
+ "(objectclass=posixGroup)",
+ realm.getGroupSearchControls()
+ );
+
+ assertEquals(
+ new HashSet(Arrays.asList("group-one", "zeppelin-role")),
+ roles
+ );
+ }
+
+ private NamingEnumeration enumerationOf(BasicAttributes... attrs) {
+ final Iterator iterator = Arrays.asList(attrs).iterator();
+ return new NamingEnumeration() {
+ @Override
+ public SearchResult next() throws NamingException {
+ return nextElement();
+ }
+
+ @Override
+ public boolean hasMore() throws NamingException {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public void close() throws NamingException {
+ }
+
+ @Override
+ public boolean hasMoreElements() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public SearchResult nextElement() {
+ final BasicAttributes attrs = iterator.next();
+ return new SearchResult(null, null, attrs);
+ }
+ };
+ }
+}
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
index ae0911cc42..7675cf6d9d 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
@@ -126,8 +126,8 @@ public abstract class AbstractTestRestApi {
private static void start(boolean withAuth) throws Exception {
if (!wasRunning) {
- System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_HOME.getVarName(), "../");
- System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_WAR.getVarName(), "../zeppelin-web/dist");
+ System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_HOME.getVarName(), new File("../").getAbsolutePath());
+ System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_WAR.getVarName(), new File("../zeppelin-web/dist").getAbsolutePath());
// some test profile does not build zeppelin-web.
// to prevent zeppelin starting up fail, create zeppelin-web/dist directory
@@ -211,6 +211,7 @@ public abstract class AbstractTestRestApi {
// set spark home for pyspark
sparkProperties.put("spark.home",
new InterpreterProperty("spark.home", getSparkHome(), InterpreterPropertyType.TEXTAREA.getValue()));
+ sparkProperties.put("zeppelin.pyspark.useIPython", new InterpreterProperty("zeppelin.pyspark.useIPython", "false", InterpreterPropertyType.TEXTAREA.getValue()));
sparkIntpSetting.setProperties(sparkProperties);
pySpark = true;
@@ -233,6 +234,8 @@ public abstract class AbstractTestRestApi {
new InterpreterProperty("spark.home", sparkHome, InterpreterPropertyType.TEXTAREA.getValue()));
sparkProperties.put("zeppelin.spark.useHiveContext",
new InterpreterProperty("zeppelin.spark.useHiveContext", false, InterpreterPropertyType.CHECKBOX.getValue()));
+ sparkProperties.put("zeppelin.pyspark.useIPython", new InterpreterProperty("zeppelin.pyspark.useIPython", "false", InterpreterPropertyType.TEXTAREA.getValue()));
+
pySpark = true;
sparkR = true;
}
@@ -304,10 +307,9 @@ public abstract class AbstractTestRestApi {
protected static void shutDown() throws Exception {
if (!wasRunning) {
// restart interpreter to stop all interpreter processes
- List settingList = ZeppelinServer.notebook.getInterpreterSettingManager()
- .getDefaultInterpreterSettingList();
- for (String setting : settingList) {
- ZeppelinServer.notebook.getInterpreterSettingManager().restart(setting);
+ List settingList = ZeppelinServer.notebook.getInterpreterSettingManager().get();
+ for (InterpreterSetting setting : settingList) {
+ ZeppelinServer.notebook.getInterpreterSettingManager().restart(setting.getId());
}
if (shiroIni != null) {
FileUtils.deleteQuietly(shiroIni);
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java
index 28541bd3fe..72dd8a7dce 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java
@@ -80,7 +80,7 @@ public class InterpreterRestApiTest extends AbstractTestRestApi {
// then
assertThat(get, isAllowed());
- assertEquals(ZeppelinServer.notebook.getInterpreterSettingManager().getAvailableInterpreterSettings().size(),
+ assertEquals(ZeppelinServer.notebook.getInterpreterSettingManager().getInterpreterSettingTemplates().size(),
body.entrySet().size());
get.releaseConnection();
}
@@ -110,7 +110,7 @@ public class InterpreterRestApiTest extends AbstractTestRestApi {
@Test
public void testSettingsCRUD() throws IOException {
// when: call create setting API
- String rawRequest = "{\"name\":\"md2\",\"group\":\"md\"," +
+ String rawRequest = "{\"name\":\"md3\",\"group\":\"md\"," +
"\"properties\":{\"propname\": {\"value\": \"propvalue\", \"name\": \"propname\", \"type\": \"textarea\"}}," +
"\"interpreterGroup\":[{\"class\":\"org.apache.zeppelin.markdown.Markdown\",\"name\":\"md\"}]," +
"\"dependencies\":[]," +
@@ -367,7 +367,7 @@ public class InterpreterRestApiTest extends AbstractTestRestApi {
@Test
public void testGetMetadataInfo() throws IOException {
- String jsonRequest = "{\"name\":\"spark\",\"group\":\"spark\"," +
+ String jsonRequest = "{\"name\":\"spark_new\",\"group\":\"spark\"," +
"\"properties\":{\"propname\": {\"value\": \"propvalue\", \"name\": \"propname\", \"type\": \"textarea\"}}," +
"\"interpreterGroup\":[{\"class\":\"org.apache.zeppelin.markdown.Markdown\",\"name\":\"md\"}]," +
"\"dependencies\":[]," +
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookSecurityRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookSecurityRestApiTest.java
index 367a199da7..c3b0977f1f 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookSecurityRestApiTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookSecurityRestApiTest.java
@@ -81,7 +81,7 @@ public class NotebookSecurityRestApiTest extends AbstractTestRestApi {
String noteId = createNoteForUser("test", "admin", "password1");
//set permission
- String payload = "{ \"owners\": [\"admin\"], \"readers\": [\"user2\"], \"writers\": [\"user2\"] }";
+ String payload = "{ \"owners\": [\"admin\"], \"readers\": [\"user2\"], \"runners\": [\"user2\"], \"writers\": [\"user2\"] }";
PutMethod put = httpPut("/notebook/" + noteId + "/permissions", payload , "admin", "password1");
assertThat("test set note permission method:", put, isAllowed());
put.releaseConnection();
@@ -98,7 +98,7 @@ public class NotebookSecurityRestApiTest extends AbstractTestRestApi {
String noteId = createNoteForUser("test", "admin", "password1");
//set permission
- String payload = "{ \"owners\": [\"admin\", \"user1\"], \"readers\": [\"user2\"], \"writers\": [\"user2\"] }";
+ String payload = "{ \"owners\": [\"admin\", \"user1\"], \"readers\": [\"user2\"], \"runners\": [\"user2\"], \"writers\": [\"user2\"] }";
PutMethod put = httpPut("/notebook/" + noteId + "/permissions", payload , "admin", "password1");
assertThat("test set note permission method:", put, isAllowed());
put.releaseConnection();
@@ -180,7 +180,7 @@ public class NotebookSecurityRestApiTest extends AbstractTestRestApi {
}
private void setPermissionForNote(String noteId, String user, String pwd) throws IOException {
- String payload = "{\"owners\":[\"" + user + "\"],\"readers\":[\"" + user + "\"],\"writers\":[\"" + user + "\"]}";
+ String payload = "{\"owners\":[\"" + user + "\"],\"readers\":[\"" + user + "\"],\"runners\":[\"" + user + "\"],\"writers\":[\"" + user + "\"]}";
PutMethod put = httpPut(("/notebook/" + noteId + "/permissions"), payload, user, pwd);
put.releaseConnection();
}
@@ -206,10 +206,11 @@ public class NotebookSecurityRestApiTest extends AbstractTestRestApi {
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) {
+ 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)));
+ writers.contains(user) || runners.contains(user)));
}
getPermission.releaseConnection();
}
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java
index 5093cb838f..2a64665b0c 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java
@@ -27,6 +27,7 @@ import com.google.common.collect.Sets;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.lang3.StringUtils;
import org.apache.zeppelin.notebook.Note;
import org.apache.zeppelin.notebook.Paragraph;
@@ -651,6 +652,43 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
ZeppelinServer.notebook.removeNote(note.getId(), anonymous);
}
+ @Test
+ public void testUpdateParagraph() throws IOException {
+ Note note = ZeppelinServer.notebook.createNote(anonymous);
+
+ String jsonRequest = "{\"title\": \"title1\", \"text\": \"text1\"}";
+ PostMethod post = httpPost("/notebook/" + note.getId() + "/paragraph", jsonRequest);
+ Map resp = gson.fromJson(post.getResponseBodyAsString(), new TypeToken