CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-co-cask-cdap--cdap-security-spi

Service Provider Interface for CDAP's security and authorization framework enabling pluggable authorization mechanisms.

Pending
Overview
Eval results
Files

authorization.mddocs/

Authorization Management

The authorization management components provide the core interfaces and implementations for controlling access to CDAP resources through role-based access control and privilege management.

Core Authorization Interface

Authorizer

The main interface that authorization extensions must implement to provide custom authorization logic.

@Beta
interface Authorizer extends PrivilegesFetcher, PrivilegesManager, AuthorizationEnforcer {
  /**
   * Initialize the Authorizer with the provided context.
   */
  void initialize(AuthorizationContext context) throws Exception;
  
  /**
   * Create a new role.
   */
  void createRole(Role role) throws Exception;
  
  /**
   * Drop a role.
   */
  void dropRole(Role role) throws Exception;
  
  /**
   * Add a role to the specified Principal.
   */
  void addRoleToPrincipal(Role role, Principal principal) throws Exception;
  
  /**
   * Remove a role from the specified Principal.
   */
  void removeRoleFromPrincipal(Role role, Principal principal) throws Exception;
  
  /**
   * List all roles for the specified Principal.
   */
  Set<Role> listRoles(Principal principal) throws Exception;
  
  /**
   * List all available roles in the system.
   */
  Set<Role> listAllRoles() throws Exception;
  
  /**
   * Cleanup method called when the authorizer is destroyed.
   */
  void destroy() throws Exception;
}

AuthorizationEnforcer

Interface for enforcing access control decisions.

@Beta
interface AuthorizationEnforcer {
  /**
   * Enforce authorization for a single action.
   */
  void enforce(EntityId entity, Principal principal, Action action) throws Exception;
  
  /**
   * Enforce authorization for multiple actions.
   */
  void enforce(EntityId entity, Principal principal, Set<Action> actions) throws Exception;
  
  /**
   * Check which entities are visible to the principal.
   */
  Set<? extends EntityId> isVisible(Set<? extends EntityId> entityIds, Principal principal) throws Exception;
}

PrivilegesManager

Interface for managing privileges on entities.

interface PrivilegesManager {
  /**
   * Grant privileges to a principal on an authorizable entity.
   */
  void grant(Authorizable authorizable, Principal principal, Set<Action> actions) throws Exception;
  
  /**
   * Revoke specific privileges from a principal on an authorizable entity.
   */
  void revoke(Authorizable authorizable, Principal principal, Set<Action> actions) throws Exception;
  
  /**
   * Revoke all privileges on an authorizable entity.
   */
  void revoke(Authorizable authorizable) throws Exception;
  
  /**
   * List all privileges for a principal.
   */
  Set<Privilege> listPrivileges(Principal principal) throws Exception;
}

PrivilegesFetcher

Interface for retrieving privilege information.

interface PrivilegesFetcher {
  /**
   * List all privileges for the specified principal.
   */
  Set<Privilege> listPrivileges(Principal principal) throws Exception;
}

Base Implementation Classes

AbstractAuthorizer

Abstract base class providing default implementations for lifecycle methods.

abstract class AbstractAuthorizer implements Authorizer {
  protected static final Predicate<EntityId> ALLOW_ALL;
  
  /**
   * Default no-op initialization.
   */
  void initialize(AuthorizationContext context) throws Exception;
  
  /**
   * Default no-op cleanup.
   */
  void destroy() throws Exception;
  
  /**
   * Single-action enforcement that delegates to multi-action method.
   */
  void enforce(EntityId entity, Principal principal, Action action) throws Exception;
}

NoOpAuthorizer

No-operation implementation used when authorization is disabled.

class NoOpAuthorizer extends AbstractAuthorizer {
  void enforce(EntityId entity, Principal principal, Set<Action> actions) throws Exception;
  Set<? extends EntityId> isVisible(Set<? extends EntityId> entityIds, Principal principal) throws Exception;
  void grant(Authorizable authorizable, Principal principal, Set<Action> actions) throws Exception;
  void revoke(Authorizable authorizable, Principal principal, Set<Action> actions) throws Exception;
  void revoke(Authorizable authorizable) throws Exception;
  void createRole(Role role);
  void dropRole(Role role);
  void addRoleToPrincipal(Role role, Principal principal);
  void removeRoleFromPrincipal(Role role, Principal principal);
  Set<Role> listRoles(Principal principal);
  Set<Role> listAllRoles();
  Set<Privilege> listPrivileges(Principal principal);
}

Authorization Context

AuthorizationContext

Context interface providing access to CDAP services for authorization extensions.

interface AuthorizationContext extends DatasetContext, Admin, Transactional, 
    AuthenticationContext, SecureStore {
  /**
   * Get extension properties from cdap-site.xml with prefix 
   * security.authorization.extension.config.
   */
  Properties getExtensionProperties();
  
  // Messaging operations (all throw UnsupportedOperationException)
  void createTopic(String topic) throws TopicAlreadyExistsException, IOException;
  void createTopic(String topic, Map<String, String> properties) throws TopicAlreadyExistsException, IOException;
  Map<String, String> getTopicProperties(String topic) throws TopicNotFoundException, IOException;
  void updateTopic(String topic, Map<String, String> properties) throws TopicNotFoundException, IOException;
  void deleteTopic(String topic) throws TopicNotFoundException, IOException;
}

Usage Examples

Custom Authorization Backend

public class LdapAuthorizer extends AbstractAuthorizer {
  private LdapConnection ldapConnection;
  private String baseDn;
  
  @Override
  public void initialize(AuthorizationContext context) throws Exception {
    Properties props = context.getExtensionProperties();
    String ldapUrl = props.getProperty("ldap.url");
    String bindDn = props.getProperty("ldap.bind.dn");
    String bindPassword = props.getProperty("ldap.bind.password");
    baseDn = props.getProperty("ldap.base.dn");
    
    ldapConnection = new LdapConnection(ldapUrl, bindDn, bindPassword);
  }
  
  @Override
  public void enforce(EntityId entity, Principal principal, Set<Action> actions) 
      throws Exception {
    // Query LDAP to check if user has required permissions
    String userDn = "uid=" + principal.getName() + "," + baseDn;
    
    for (Action action : actions) {
      if (!hasLdapPermission(userDn, entity, action)) {
        throw new UnauthorizedException(principal, action, entity);
      }
    }
  }
  
  @Override
  public void grant(Authorizable authorizable, Principal principal, Set<Action> actions) 
      throws Exception {
    // Add LDAP group membership or attributes
    String userDn = "uid=" + principal.getName() + "," + baseDn;
    for (Action action : actions) {
      String groupDn = buildPermissionGroupDn(authorizable, action);
      ldapConnection.addUserToGroup(userDn, groupDn);
    }
  }
  
  @Override 
  public Set<Role> listRoles(Principal principal) throws Exception {
    // Query LDAP groups for user
    String userDn = "uid=" + principal.getName() + "," + baseDn;
    return ldapConnection.getUserGroups(userDn)
        .stream()
        .map(groupName -> new Role(groupName))
        .collect(Collectors.toSet());
  }
  
  @Override
  public void destroy() throws Exception {
    if (ldapConnection != null) {
      ldapConnection.close();
    }
  }
  
  private boolean hasLdapPermission(String userDn, EntityId entity, Action action) {
    // Implementation specific to your LDAP schema
    return false;
  }
  
  private String buildPermissionGroupDn(Authorizable authorizable, Action action) {
    // Build group DN based on your LDAP schema
    return "cn=" + authorizable.toString() + "-" + action.name() + "," + baseDn;
  }
}

Role-Based Access Control

public class SimpleRoleAuthorizer extends AbstractAuthorizer {
  private Map<String, Set<Role>> userRoles = new HashMap<>();
  private Map<Role, Set<Privilege>> rolePrivileges = new HashMap<>();
  
  @Override
  public void createRole(Role role) throws Exception {
    if (rolePrivileges.containsKey(role)) {
      throw new AlreadyExistsException(role);
    }
    rolePrivileges.put(role, new HashSet<>());
  }
  
  @Override
  public void addRoleToPrincipal(Role role, Principal principal) throws Exception {
    if (!rolePrivileges.containsKey(role)) {
      throw new NotFoundException(role);
    }
    userRoles.computeIfAbsent(principal.getName(), k -> new HashSet<>()).add(role);
  }
  
  @Override
  public void grant(Authorizable authorizable, Principal principal, Set<Action> actions) 
      throws Exception {
    // If granting to a role, update role privileges
    if (principal.getType() == PrincipalType.ROLE) {
      Role role = new Role(principal.getName());
      Set<Privilege> privileges = rolePrivileges.get(role);
      if (privileges != null) {
        for (Action action : actions) {
          privileges.add(new Privilege(authorizable, action));
        }
      }
    }
  }
  
  @Override
  public void enforce(EntityId entity, Principal principal, Set<Action> actions) 
      throws Exception {
    Set<Privilege> userPrivileges = getUserPrivileges(principal);
    
    for (Action action : actions) {
      boolean hasPermission = userPrivileges.stream()
          .anyMatch(p -> p.getAction().equals(action) && 
                         entityMatches(p.getAuthorizable(), entity));
      
      if (!hasPermission) {
        throw new UnauthorizedException(principal, action, entity);
      }
    }
  }
  
  private Set<Privilege> getUserPrivileges(Principal principal) {
    Set<Privilege> privileges = new HashSet<>();
    Set<Role> roles = userRoles.get(principal.getName());
    
    if (roles != null) {
      for (Role role : roles) {
        Set<Privilege> rolePrivs = rolePrivileges.get(role);
        if (rolePrivs != null) {
          privileges.addAll(rolePrivs);
        }
      }
    }
    
    return privileges;
  }
  
  private boolean entityMatches(Authorizable authorizable, EntityId entity) {
    // Implementation-specific logic to match entities
    return authorizable.toString().equals(entity.toString());
  }
}

Install with Tessl CLI

npx tessl i tessl/maven-co-cask-cdap--cdap-security-spi

docs

authentication.md

authorization.md

exceptions.md

index.md

tile.json