diff --git a/conf/shiro.ini b/conf/shiro.ini
index ca5afe3471b..75a3fb9bd91 100644
--- a/conf/shiro.ini
+++ b/conf/shiro.ini
@@ -42,6 +42,11 @@ user3 = password4, role2
#ldapRealm.userDnTemplate = uid={0},ou=Users,dc=COMPANY,dc=COM
#ldapRealm.contextFactory.authenticationMechanism = SIMPLE
+### A sample for configuring ZeppelinHub Realm
+#zeppelinHubRealm = org.apache.zeppelin.realm.ZeppelinHubRealm
+## Url of ZeppelinHub
+#zeppelinHubRealm.zeppelinhubUrl = https://www.zeppelinhub.com
+#securityManager.realms = $zeppelinHubRealm
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
diff --git a/docs/security/shiroauthentication.md b/docs/security/shiroauthentication.md
index a5c9c317b36..2f3590a2332 100644
--- a/docs/security/shiroauthentication.md
+++ b/docs/security/shiroauthentication.md
@@ -105,6 +105,33 @@ finance = *
group1 = *
```
+## Configure Realm (optional)
+Realms are responsible for authentication and authorization in Apache Zeppelin. By default, Apache Zeppelin uses [IniRealm](https://shiro.apache.org/static/latest/apidocs/org/apache/shiro/realm/text/IniRealm.html) (users and groups are configurable in `conf/shiro.ini` file under `[user]` and `[group]` section). You can also leverage Shiro Realms like [JndiLdapRealm](https://shiro.apache.org/static/latest/apidocs/org/apache/shiro/realm/ldap/JndiLdapRealm.html), [JdbcRealm](https://shiro.apache.org/static/latest/apidocs/org/apache/shiro/realm/jdbc/JdbcRealm.html) or create [our own](https://shiro.apache.org/static/latest/apidocs/org/apache/shiro/realm/AuthorizingRealm.html).
+To learn more about Apache Shiro Realm, please check [this documentation](http://shiro.apache.org/realm.html).
+
+We also provide community custom Realms.
+
+### Active Directory
+TBD
+
+### LDAP
+TBD
+
+### ZeppelinHub
+[ZeppelinHub](https://www.zeppelinhub.com) is a service that synchronize your Apache Zeppelin notebooks and enables you to collaborate easily.
+
+To enable login with your ZeppelinHub credential, apply the following change in `conf/shiro.ini` under `[main]` section.
+
+```
+### A sample for configuring ZeppelinHub Realm
+zeppelinHubRealm = org.apache.zeppelin.realm.ZeppelinHubRealm
+## Url of ZeppelinHub
+zeppelinHubRealm.zeppelinhubUrl = https://www.zeppelinhub.com
+securityManager.realms = $zeppelinHubRealm
+```
+
+> Note: ZeppelinHub is not releated to apache Zeppelin project.
+
## Secure your Zeppelin information (optional)
By default, anyone who defined in `[users]` can share **Interpreter Setting**, **Credential** and **Configuration** information in Apache Zeppelin.
Sometimes you might want to hide these information for your use case.
@@ -123,3 +150,4 @@ If you want to grant this permission to other users, you can change **roles[ ]**
> **NOTE :** All of the above configurations are defined in the `conf/shiro.ini` file. This documentation is originally from [SECURITY-README.md](https://github.com/apache/zeppelin/blob/master/SECURITY-README.md).
+
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ZeppelinHubRealm.java b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ZeppelinHubRealm.java
new file mode 100644
index 00000000000..cbe490d8de5
--- /dev/null
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ZeppelinHubRealm.java
@@ -0,0 +1,199 @@
+/*
+ * 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.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.commons.httpclient.methods.StringRequestEntity;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.authc.AccountException;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Joiner;
+import com.google.gson.Gson;
+import com.google.gson.JsonParseException;
+
+/**
+ * A {@code Realm} implementation that uses the ZeppelinHub to authenticate users.
+ *
+ */
+public class ZeppelinHubRealm extends AuthorizingRealm {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ZeppelinHubRealm.class);
+ private static final String DEFAULT_ZEPPELINHUB_URL = "https://www.zeppelinhub.com";
+ private static final String USER_LOGIN_API_ENDPOINT = "api/v1/users/login";
+ private static final String JSON_CONTENT_TYPE = "application/json";
+ private static final String UTF_8_ENCODING = "UTF-8";
+ private static final AtomicInteger INSTANCE_COUNT = new AtomicInteger();
+
+ private final HttpClient httpClient;
+ private final Gson gson;
+
+ private String zeppelinhubUrl;
+ private String name;
+
+ public ZeppelinHubRealm() {
+ super();
+ LOG.debug("Init ZeppelinhubRealm");
+ //TODO(anthonyc): think about more setting for this HTTP client.
+ // eg: if user uses proxy etcetc...
+ httpClient = new HttpClient();
+ gson = new Gson();
+ name = getClass().getName() + "_" + INSTANCE_COUNT.getAndIncrement();
+ }
+
+ @Override
+ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authToken)
+ throws AuthenticationException {
+ UsernamePasswordToken token = (UsernamePasswordToken) authToken;
+ if (StringUtils.isBlank(token.getUsername())) {
+ throw new AccountException("Empty usernames are not allowed by this realm.");
+ }
+ String loginPayload = createLoginPayload(token.getUsername(), token.getPassword());
+ User user = authenticateUser(loginPayload);
+ LOG.debug("{} successfully login via ZeppelinHub", user.login);
+ return new SimpleAuthenticationInfo(user.login, token.getPassword(), name);
+ }
+
+ @Override
+ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+ // TODO(xxx): future work will be done here.
+ return null;
+ }
+
+ protected void onInit() {
+ super.onInit();
+ }
+
+ /**
+ * Setter of ZeppelinHub URL, this will be called by Shiro based on zeppelinhubUrl property
+ * in shiro.ini file.
+ * {
+ * 'login': 'userLogin',
+ * 'password': 'userpassword'
+ * }
+ *
+ * @param login
+ * @param pwd
+ * @return
+ */
+ protected String createLoginPayload(String login, char[] pwd) {
+ StringBuilder sb = new StringBuilder("{\"login\":\"");
+ return sb.append(login).append("\", \"password\":\"").append(pwd).append("\"}").toString();
+ }
+
+ /**
+ * Perform a Simple URL check by using URI(url).toURL().
+ * If the url is not valid, the try-catch condition will catch the exceptions and return false,
+ * otherwise true will be returned.
+ *
+ * @param url
+ * @return
+ */
+ protected boolean isZeppelinHubUrlValid(String url) {
+ boolean valid;
+ try {
+ new URI(url).toURL();
+ valid = true;
+ } catch (URISyntaxException | MalformedURLException e) {
+ LOG.error("Zeppelinhub url is not valid, default ZeppelinHub url will be used.", e);
+ valid = false;
+ }
+ return valid;
+ }
+
+ /**
+ * Helper class that will be use to deserialize ZeppelinHub response.
+ */
+ protected class User {
+ public String login;
+ public String email;
+ public String name;
+ }
+}