/* * Copyright (c) 2013 Oracle Corporation. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Winston Prakash */ package org.eclipse.hudson.security.team; import hudson.model.Computer; import hudson.model.Hudson; import hudson.model.Item; import hudson.model.Job; import hudson.model.MyViewsProperty; import hudson.model.View; import hudson.security.Permission; import hudson.security.SecurityRealm; import hudson.security.SidACL; import org.eclipse.hudson.security.HudsonSecurityEntitiesHolder; import org.eclipse.hudson.security.HudsonSecurityManager; import org.eclipse.hudson.security.team.TeamManager.TeamNotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.acls.model.Sid; /** * Team based authorization * * @since 3.1.0 * @author Winston Prakash */ public class TeamBasedACL extends SidACL { private static Logger LOGGER = LoggerFactory.getLogger(TeamBasedACL.class); public enum SCOPE { GLOBAL, TEAM_MANAGEMENT, TEAM, JOB, VIEW, NODE }; private final SCOPE scope; private final TeamManager teamManager; private Job job; private View view; private Computer node; private Team team; public TeamBasedACL(TeamManager teamManager, SCOPE scope) { this.teamManager = teamManager; this.scope = scope; } public TeamBasedACL(TeamManager teamManager, SCOPE scope, Job job) { this(teamManager, scope); this.job = job; } public TeamBasedACL(TeamManager teamManager, SCOPE scope, View view) { this(teamManager, scope); this.view = view; } public TeamBasedACL(TeamManager teamManager, SCOPE scope, Computer node) { this(teamManager, scope); this.node = node; } public TeamBasedACL(TeamManager teamManager, SCOPE scope, Team team) { this(teamManager, scope); this.team = team; } @Override protected Boolean hasPermission(Sid sid, Permission permission) { String userName = toString(sid); // SysAdmin gets all permission if (teamManager.isSysAdmin(userName)) { return true; } if (scope == SCOPE.TEAM_MANAGEMENT) { //Only Sysadmin gets to do Team Management if (teamManager.isSysAdmin(userName)) { return true; } } if (scope == SCOPE.GLOBAL) { //All non team members gets only READ Permission if (permission.getImpliedBy() == Permission.READ) { return true; } // Member of any of the team with JOB CREATE Permission can create Job if (permission == Item.CREATE) { for (Team userTeam : teamManager.findUserTeams(userName)) { if (isTeamAwareSecurityRealm()) { return true; // for now give full permission to all team members } TeamMember member = userTeam.findMember(userName); if ((member != null) && member.hasPermission(Item.CREATE)) { return true; } } } // Member of any of the team with View CREATE Permission can create View if (permission == View.CREATE) { for (Team userTeam : teamManager.findUserTeams(userName)) { TeamMember member = userTeam.findMember(userName); if ((member != null) && member.hasPermission(View.CREATE)) { return true; } } } // Member of any of the team with Node CREATE Permission can create Node if (permission == Computer.CREATE) { for (Team userTeam : teamManager.findUserTeams(userName)) { TeamMember member = userTeam.findMember(userName); if ((member != null) && member.hasPermission(Computer.CREATE)) { return true; } } } } if (scope == SCOPE.TEAM) { // Sysadmin gets to do all team maintenance operations if (teamManager.isSysAdmin(userName)) { return true; } for (Team userTeam : teamManager.findUserTeams(userName)) { if (userTeam == team) { // Team admin gets to do all team maintenance operations if (userTeam.isAdmin(userName)) { return true; } else if (userTeam.isMember(userName) && permission.getImpliedBy() == Permission.READ) { return true; } } } } if (scope == SCOPE.JOB) { Team jobTeam = teamManager.findJobOwnerTeam(job.getName()); if (jobTeam != null) { if (jobTeam.isMember(userName)) { // All members of the team get read permission if (permission.getImpliedBy() == Permission.READ) { return true; } if (isTeamAwareSecurityRealm()) { return true; // for now give full permission to all team members } else { TeamMember member = jobTeam.findMember(userName); return member.hasPermission(permission); } } } // Grant Read permission to Public Jobs and jobs based on visibility if (permission.getImpliedBy() == Permission.READ) { if (hasReadPermission(jobTeam, permission, userName)) { return true; } } if (permission == Item.EXTENDED_READ) { if (hasReadPermission(jobTeam, permission, userName)) { if (jobTeam != null) { TeamJob teamJob = jobTeam.findJob(job.getName()); if (teamJob.isAllowConfigView()) { return true; } } } } } if (scope == SCOPE.VIEW) { Team viewTeam = teamManager.findViewOwnerTeam(view.getViewName()); // Member with Item.CREATE Permissions can create Job from this View scope if (permission == Item.CREATE) { for (Team userTeam : teamManager.findUserTeams(userName)) { TeamMember member = userTeam.findMember(userName); if ((member != null) && member.hasPermission(Item.CREATE)) { return true; } } } // Member with Computer.CREATE Permissions can create Node from this View scope if (permission == Computer.CREATE) { for (Team userTeam : teamManager.findUserTeams(userName)) { TeamMember member = userTeam.findMember(userName); if ((member != null) && member.hasPermission(Computer.CREATE)) { return true; } } } // Member of any of the team with View CREATE Permission can create View if (permission == View.CREATE) { for (Team userTeam : teamManager.findUserTeams(userName)) { TeamMember member = userTeam.findMember(userName); if ((member != null) && member.hasPermission(View.CREATE)) { return true; } } } // In case of My Views the view is not managed by Team, so just check if the // user has appropriate permission if (view.getOwner() instanceof MyViewsProperty) { if ((permission == View.CONFIGURE) || (permission == View.DELETE)) { for (Team userTeam : teamManager.findUserTeams(userName)) { TeamMember member = userTeam.findMember(userName); if ((member != null) && member.hasPermission(permission)) { return true; } } } } if (viewTeam != null) { if (viewTeam.isMember(userName)) { // All members of the team get read permission if (permission == View.READ) { return true; } TeamMember member = viewTeam.findMember(userName); return member.hasPermission(permission); } } // Grant Read permission to Public Jobs and jobs based on visibility if (permission == View.READ) { if (hasViewReadPermission(viewTeam, permission, userName)) { return true; } } } if (scope == SCOPE.NODE) { String nodeName = node.getName(); if (node instanceof Hudson.MasterComputer) { nodeName = "Master"; } Team nodeTeam = teamManager.findNodeOwnerTeam(nodeName); // Member of any of the team with Node CREATE Permission can create Node if (permission == Computer.CREATE) { for (Team userTeam : teamManager.findUserTeams(userName)) { TeamMember member = userTeam.findMember(userName); if ((member != null) && member.hasPermission(Computer.CREATE)) { return true; } } } if (nodeTeam != null) { if (nodeTeam.isMember(userName)) { // All members of the team get read permission if (permission == Computer.READ) { return true; } TeamMember member = nodeTeam.findMember(userName); return member.hasPermission(permission); } } // Grant Read permission to Public Jobs and jobs based on visibility if (permission == Computer.READ) { if (hasNodeReadPermission(nodeTeam, permission, userName)) { return true; } } } return null; } private boolean hasReadPermission(Team jobTeam, Permission permission, String userName) { // Grant Read permission to Public Jobs and jobs based on visibility try { Team publicTeam = teamManager.findTeam(PublicTeam.PUBLIC_TEAM_NAME); if (publicTeam.isJobOwner(job.getName())) { if (permission.getImpliedBy() == Permission.READ) { return true; } } } catch (TeamNotFoundException ex) { LOGGER.error("The public team must exists.", ex); } if (jobTeam != null) { TeamJob teamJob = jobTeam.findJob(job.getName()); for (Team userTeam : teamManager.findUserTeams(userName)) { if (teamJob.isVisible(userTeam.getName())) { return true; } } if (teamJob.isVisible(PublicTeam.PUBLIC_TEAM_NAME)) { return true; } } return false; } private boolean hasViewReadPermission(Team viewTeam, Permission permission, String userName) { // Grant Read permission to Public Views and views based on visibility try { Team publicTeam = teamManager.findTeam(PublicTeam.PUBLIC_TEAM_NAME); if (publicTeam.isViewOwner(view.getViewName())) { if (permission == View.READ) { return true; } } } catch (TeamNotFoundException ex) { LOGGER.error("The public team must exists.", ex); } if (viewTeam != null) { TeamView teamView = viewTeam.findView(view.getViewName()); for (Team userTeam : teamManager.findUserTeams(userName)) { if (teamView.isVisible(userTeam.getName())) { return true; } } if (teamView.isVisible(PublicTeam.PUBLIC_TEAM_NAME)) { return true; } } return false; } private boolean hasNodeReadPermission(Team nodeTeam, Permission permission, String userName) { String nodeName = node.getName(); if (node instanceof Hudson.MasterComputer) { nodeName = "Master"; } // Grant Read permission to Public Views and views based on visibility try { Team publicTeam = teamManager.findTeam(PublicTeam.PUBLIC_TEAM_NAME); if (publicTeam.isNodeOwner(nodeName)) { if (permission == Computer.READ) { return true; } } } catch (TeamNotFoundException ex) { LOGGER.error("The public team must exists.", ex); } if (nodeTeam != null) { TeamNode teamNode = nodeTeam.findNode(nodeName); for (Team userTeam : teamManager.findUserTeams(userName)) { if (teamNode.isVisible(userTeam.getName())) { return true; } } if (teamNode.isVisible(PublicTeam.PUBLIC_TEAM_NAME)) { return true; } } return false; } private boolean isTeamAwareSecurityRealm() { HudsonSecurityManager hudsonSecurityManager = HudsonSecurityEntitiesHolder.getHudsonSecurityManager(); SecurityRealm securityRealm = null; if (hudsonSecurityManager != null) { securityRealm = hudsonSecurityManager.getSecurityRealm(); } if ((securityRealm != null) && securityRealm instanceof TeamAwareSecurityRealm) { return true; } return false; } }