azkaban-developers
Details
conf/azkaban.properties 2(+2 -0)
diff --git a/conf/azkaban.properties b/conf/azkaban.properties
index c222cfb..7884f10 100644
--- a/conf/azkaban.properties
+++ b/conf/azkaban.properties
@@ -45,3 +45,5 @@ mail.sender=
mail.host=
job.failure.email=
job.success.email=
+
+lockdown.create.projects=false
\ No newline at end of file
diff --git a/src/java/azkaban/user/Permission.java b/src/java/azkaban/user/Permission.java
index 7f57290..9f26055 100644
--- a/src/java/azkaban/user/Permission.java
+++ b/src/java/azkaban/user/Permission.java
@@ -29,6 +29,7 @@ public class Permission {
WRITE(0x0000002),
EXECUTE(0x0000004),
SCHEDULE(0x0000008),
+ CREATEPROJECTS(0x40000000), // Only used for roles
ADMIN(0x8000000);
private int numVal;
src/java/azkaban/user/XmlUserManager.java 53(+50 -3)
diff --git a/src/java/azkaban/user/XmlUserManager.java b/src/java/azkaban/user/XmlUserManager.java
index 7c26daf..042a081 100644
--- a/src/java/azkaban/user/XmlUserManager.java
+++ b/src/java/azkaban/user/XmlUserManager.java
@@ -20,6 +20,7 @@ import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -49,6 +50,7 @@ public class XmlUserManager implements UserManager {
public static final String AZKABAN_USERS_TAG = "azkaban-users";
public static final String USER_TAG = "user";
public static final String ROLE_TAG = "role";
+ public static final String GROUP_TAG = "group";
public static final String ROLENAME_ATTR = "name";
public static final String ROLEPERMISSIONS_ATTR = "permissions";
public static final String USERNAME_ATTR = "username";
@@ -56,12 +58,14 @@ public class XmlUserManager implements UserManager {
public static final String ROLES_ATTR = "roles";
public static final String PROXY_ATTR = "proxy";
public static final String GROUPS_ATTR = "groups";
-
+ public static final String GROUPNAME_ATTR = "name";
+
private String xmlPath;
private HashMap<String, User> users;
private HashMap<String, String> userPassword;
private HashMap<String, Role> roles;
+ private HashMap<String, Set<String>> groupRoles;
private HashMap<String, HashSet<String>> proxyUserMap;
/**
@@ -84,8 +88,9 @@ public class XmlUserManager implements UserManager {
HashMap<String, User> users = new HashMap<String, User>();
HashMap<String, String> userPassword = new HashMap<String, String>();
HashMap<String, Role> roles = new HashMap<String, Role>();
+ HashMap<String, Set<String>> groupRoles = new HashMap<String, Set<String>>();
HashMap<String, HashSet<String>> proxyUserMap = new HashMap<String, HashSet<String>>();
-
+
// Creating the document builder to parse xml.
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
.newInstance();
@@ -122,6 +127,9 @@ public class XmlUserManager implements UserManager {
else if (node.getNodeName().equals(ROLE_TAG)) {
parseRoleTag(node, roles);
}
+ else if (node.getNodeName().equals(GROUP_TAG)) {
+ parseGroupRoleTag(node, groupRoles);
+ }
}
}
@@ -131,6 +139,7 @@ public class XmlUserManager implements UserManager {
this.userPassword = userPassword;
this.roles = roles;
this.proxyUserMap = proxyUserMap;
+ this.groupRoles = groupRoles;
}
}
@@ -251,9 +260,47 @@ public class XmlUserManager implements UserManager {
if (user == null) {
throw new UserManagerException("Internal error: User not found.");
}
+
+ // Add all the roles the group has to the user
+ resolveGroupRoles(user);
return user;
}
+ private void resolveGroupRoles(User user) {
+ for (String group: user.getGroups()) {
+ Set<String> groupRoleSet = groupRoles.get(group);
+ if (groupRoleSet != null) {
+ for (String role: groupRoleSet) {
+ user.addRole(role);
+ }
+ }
+ }
+ }
+
+ private void parseGroupRoleTag(Node node, HashMap<String, Set<String>> groupRoles) {
+ NamedNodeMap groupAttrMap = node.getAttributes();
+ Node groupNameAttr = groupAttrMap.getNamedItem(GROUPNAME_ATTR);
+ if (groupNameAttr == null) {
+ throw new RuntimeException(
+ "Error loading role. The role 'name' attribute doesn't exist");
+ }
+
+ String groupName = groupNameAttr.getNodeValue();
+ Set<String> roleSet = new HashSet<String>();
+
+ Node roles = groupAttrMap.getNamedItem(ROLES_ATTR);
+ if (roles != null) {
+ String value = roles.getNodeValue();
+ String[] roleSplit = value.split("\\s*,\\s*");
+ for (String role : roleSplit) {
+ roleSet.add(role);
+ }
+ }
+
+ groupRoles.put( groupName, roleSet );
+ logger.info("Group roles " + groupName + " added.");
+ }
+
@Override
public boolean validateUser(String username) {
return users.containsKey(username);
@@ -269,7 +316,7 @@ public class XmlUserManager implements UserManager {
// Return true. Validation should be added when groups are added to the xml.
return true;
}
-
+
@Override
public boolean validateProxyUser(String proxyUser, User realUser) {
if(proxyUserMap.containsKey(realUser.getUserId()) && proxyUserMap.get(realUser.getUserId()).contains(proxyUser)) {
diff --git a/src/java/azkaban/webapp/AzkabanWebServer.java b/src/java/azkaban/webapp/AzkabanWebServer.java
index 7494878..1af216f 100644
--- a/src/java/azkaban/webapp/AzkabanWebServer.java
+++ b/src/java/azkaban/webapp/AzkabanWebServer.java
@@ -144,9 +144,6 @@ public class AzkabanWebServer implements AzkabanServer {
private MBeanServer mbeanServer;
private ArrayList<ObjectName> registeredMBeans = new ArrayList<ObjectName>();
-
-
-
/**
* Constructor usually called by tomcat AzkabanServletContext to create the
* initial server
diff --git a/src/java/azkaban/webapp/servlet/IndexServlet.java b/src/java/azkaban/webapp/servlet/IndexServlet.java
index 895e766..cf94e93 100644
--- a/src/java/azkaban/webapp/servlet/IndexServlet.java
+++ b/src/java/azkaban/webapp/servlet/IndexServlet.java
@@ -19,15 +19,23 @@ package azkaban.webapp.servlet;
import java.io.IOException;
import java.util.List;
+import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.log4j.Logger;
+
//import org.apache.log4j.Logger;
+import azkaban.executor.ExecutorManager;
import azkaban.project.Project;
import azkaban.project.ProjectManager;
+import azkaban.scheduler.ScheduleManager;
+import azkaban.user.Permission;
+import azkaban.user.Role;
import azkaban.user.User;
+import azkaban.user.UserManager;
import azkaban.webapp.AzkabanWebServer;
import azkaban.webapp.session.Session;
@@ -35,11 +43,27 @@ import azkaban.webapp.session.Session;
* The main page
*/
public class IndexServlet extends LoginAbstractAzkabanServlet {
- // private static final Logger logger =
- // Logger.getLogger(IndexServlet.class.getName());
-
+ private static final Logger logger = Logger.getLogger(IndexServlet.class.getName());
+ private static final String LOCKDOWN_CREATE_PROJECTS_KEY = "lockdown.create.projects";
private static final long serialVersionUID = -1;
+ private UserManager userManager;
+
+ private boolean lockdownCreateProjects = false;
+
+ @Override
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+
+ AzkabanWebServer server = (AzkabanWebServer)getApplication();
+
+ userManager = server.getUserManager();
+ lockdownCreateProjects = server.getServerProps().getBoolean(LOCKDOWN_CREATE_PROJECTS_KEY, false);
+ if (lockdownCreateProjects) {
+ logger.info("Creation of projects is locked down");
+ }
+ }
+
@Override
protected void handleGet(HttpServletRequest req, HttpServletResponse resp, Session session) throws ServletException, IOException {
@@ -58,6 +82,11 @@ public class IndexServlet extends LoginAbstractAzkabanServlet {
ProjectManager manager = ((AzkabanWebServer)getApplication()).getProjectManager();
Page page = newPage(req, resp, session, "azkaban/webapp/servlet/velocity/index.vm");
+
+ if (lockdownCreateProjects && !hasPermissionToCreateProject(user)) {
+ page.add("hideCreateProject", true);
+ }
+
if (hasParam(req, "all")) {
List<Project> projects = manager.getProjects();
page.add("allProjects", "true");
@@ -98,5 +127,15 @@ public class IndexServlet extends LoginAbstractAzkabanServlet {
}
-
+ private boolean hasPermissionToCreateProject(User user) {
+ for(String roleName: user.getRoles()) {
+ Role role = userManager.getRole(roleName);
+ Permission perm = role.getPermission();
+ if (perm.isPermissionSet(Permission.Type.ADMIN) || perm.isPermissionSet(Permission.Type.CREATEPROJECTS)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java b/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
index fe3999c..30cb415 100644
--- a/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
+++ b/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
@@ -73,12 +73,15 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
private static final long serialVersionUID = 1;
private static final Logger logger = Logger.getLogger(ProjectManagerServlet.class);
private static final NodeLevelComparator NODE_LEVEL_COMPARATOR = new NodeLevelComparator();
+ private static final String LOCKDOWN_CREATE_PROJECTS_KEY = "lockdown.create.projects";
private ProjectManager projectManager;
private ExecutorManager executorManager;
private ScheduleManager scheduleManager;
private UserManager userManager;
+ private boolean lockdownCreateProjects = false;
+
private static Comparator<Flow> FLOW_ID_COMPARATOR = new Comparator<Flow>() {
@Override
public int compare(Flow f1, Flow f2) {
@@ -95,6 +98,10 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
executorManager = server.getExecutorManager();
scheduleManager = server.getScheduleManager();
userManager = server.getUserManager();
+ lockdownCreateProjects = server.getServerProps().getBoolean(LOCKDOWN_CREATE_PROJECTS_KEY, false);
+ if (lockdownCreateProjects) {
+ logger.info("Creation of projects is locked down");
+ }
}
@Override
@@ -137,7 +144,7 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
page.add("errorMsg", "No project set.");
page.render();
}
-
+
@Override
protected void handleMultiformPost(HttpServletRequest req, HttpServletResponse resp, Map<String, Object> params, Session session) throws ServletException, IOException {
if (params.containsKey("action")) {
@@ -1177,23 +1184,30 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
logger.info("Create project " + projectName);
User user = session.getUser();
-
+
String status = null;
String action = null;
String message = null;
HashMap<String, Object> params = null;
- try {
- projectManager.createProject(projectName, projectDescription, user);
- status = "success";
- action = "redirect";
- String redirect = "manager?project=" + projectName;
- params = new HashMap<String, Object>();
- params.put("path", redirect);
- } catch (ProjectManagerException e) {
- message = e.getMessage();
+
+ if (lockdownCreateProjects && !hasPermissionToCreateProject(user)) {
+ message = "User " + user.getUserId() + " doesn't have permission to create projects.";
+ logger.info(message);
status = "error";
}
-
+ else {
+ try {
+ projectManager.createProject(projectName, projectDescription, user);
+ status = "success";
+ action = "redirect";
+ String redirect = "manager?project=" + projectName;
+ params = new HashMap<String, Object>();
+ params.put("path", redirect);
+ } catch (ProjectManagerException e) {
+ message = e.getMessage();
+ status = "error";
+ }
+ }
String response = createJsonResponse(status, message, action, params);
try {
Writer write = resp.getWriter();
@@ -1321,4 +1335,16 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
return perm;
}
+
+ private boolean hasPermissionToCreateProject(User user) {
+ for(String roleName: user.getRoles()) {
+ Role role = userManager.getRole(roleName);
+ Permission perm = role.getPermission();
+ if (perm.isPermissionSet(Permission.Type.ADMIN) || perm.isPermissionSet(Permission.Type.CREATEPROJECTS)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/src/java/azkaban/webapp/servlet/velocity/index.vm b/src/java/azkaban/webapp/servlet/velocity/index.vm
index dc32de9..d884bb7 100644
--- a/src/java/azkaban/webapp/servlet/velocity/index.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/index.vm
@@ -66,8 +66,10 @@
#end
<input id="searchtextbox" type="text" placeholder="project name containing ..." value=#if($search_term) ${search_term} #else "" #end class="search-input" name="searchterm">
</form>
-
+
+#if (!$hideCreateProject)
<a id="create-project-btn" class="btn1 " href="#">Create Project</a>
+#end
</div><!-- end .section-hd -->
</div>
<table id="all-jobs" class="all-jobs job-table project-table">