package io.robe.auth.token; import io.dropwizard.auth.AuthenticationException; import io.dropwizard.auth.Authenticator; import io.robe.auth.data.entry.*; import io.robe.auth.data.store.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.HashSet; import java.util.Optional; import java.util.Set; /** * Authenticator implementation for token based authentication. */ public class TokenAuthenticator implements Authenticator<String, BasicToken> { private static final Logger LOGGER = LoggerFactory.getLogger(TokenAuthenticator.class); private final ServiceStore serviceStore; private final UserStore userStore; private final RoleStore roleStore; private final PermissionStore permissionStore; private final RoleGroupStore roleGroupStore; /** * Creates an instance of TokenBasedAuthenticator with the store classes. * * @param userStore Store for getting user. * @param serviceStore Store for getting service info. */ public TokenAuthenticator(UserStore userStore, ServiceStore serviceStore, RoleStore roleStore, PermissionStore permissionStore, RoleGroupStore roleGroupStore) { this.userStore = userStore; this.serviceStore = serviceStore; this.roleStore = roleStore; this.permissionStore = permissionStore; this.roleGroupStore = roleGroupStore; } /** * Creates {@link Optional} {@link io.robe.auth.Credentials} instance from provided tokenString * * @param tokenString tokenString to decode. * @return Optional instance of a {@link io.robe.auth.Credentials} which created from tokenString * @throws AuthenticationException */ @Override public Optional<BasicToken> authenticate(String tokenString) throws AuthenticationException { tokenString = tokenString.replaceAll("\"", ""); LOGGER.debug("Authenticating from database: " + tokenString); try { // Decode tokenString and get user BasicToken token = new BasicToken(tokenString); Optional<UserEntry> user = (Optional<UserEntry>) userStore.findByUsername(token.getUsername()); if (!user.isPresent()) { LOGGER.warn("User is not available: " + tokenString); return Optional.empty(); } // If user exists and active than check Service Permissions for authorization controls if (user.get().isActive()) { if (token.getPermissions() == null) { LOGGER.debug("Loading Permissions from DB: " + tokenString); Set<String> permissions = new HashSet<String>(); Set<PermissionEntry> rolePermissions = new HashSet<PermissionEntry>(); //If user role is a group than add sub role permissions to group Optional<RoleEntry> role = (Optional<RoleEntry>) roleStore.findByRoleId(user.get().getRoleId()); getAllRolePermissions(role.get(), rolePermissions); for (PermissionEntry permission : rolePermissions) { if (permission.getType().equals(PermissionEntry.Type.SERVICE)) { Optional<? extends ServiceEntry> service = serviceStore.findByCode(permission.getRestrictedItemId()); if (service.isPresent()) { permissions.add(service.get().getPath() + ":" + service.get().getMethod()); } } } // Create credentials with user info and permission list token.setPermissions(Collections.unmodifiableSet(permissions)); } else { LOGGER.debug("Loading Permissions from Cache: " + tokenString); } return Optional.ofNullable(token); } } catch (Exception e) { LOGGER.error(tokenString, e); } return Optional.empty(); } /** * Fill permission list with role and sub-role permissions recursively. * * @param parent Role to traverse. * @param rolePermissions list of all permissions of the given role. */ private void getAllRolePermissions(RoleEntry parent, Set<PermissionEntry> rolePermissions) { rolePermissions.addAll(permissionStore.findByRoleId(parent.getId())); Set<RoleGroupEntry> roleGroupEntries = (Set<RoleGroupEntry>) roleGroupStore.findByGroupId(parent.getId()); for (RoleGroupEntry entry : roleGroupEntries) { Optional<RoleEntry> role = (Optional<RoleEntry>) roleStore.findByRoleId(entry.getRoleId()); getAllRolePermissions(role.get(), rolePermissions); } } }