-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Removed unnecessary jackson annotations to address enunciate issues * bumped release version * bumped versions for some modules * Updated with latest changes from main/integration * Implemented authorization and query federation for the query microservices
- Loading branch information
Showing
3 changed files
with
157 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
src/main/java/datawave/security/authorization/ConditionalRemoteUserOperations.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package datawave.security.authorization; | ||
|
||
import java.util.Collections; | ||
import java.util.function.Function; | ||
import java.util.function.Supplier; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import datawave.user.AuthorizationsListBase; | ||
import datawave.webservice.result.GenericResponse; | ||
|
||
/** | ||
* A conditional remote user operations will only invoke the delegate remote service base on a specified function of the specified principal. For example we may | ||
* only need to invoke the remote user operations if we know the remote system will have additional auths that this user will need for the query logic being | ||
* invoked. | ||
* | ||
* An example may be a composite query that call a local and a remote query logic. Perhaps we can already tell that the user will not be able to get any | ||
* additional authorities from the remote system and hence the remote call will not be required. | ||
*/ | ||
public class ConditionalRemoteUserOperations implements UserOperations { | ||
private static final Logger log = LoggerFactory.getLogger(ConditionalRemoteUserOperations.class); | ||
|
||
private UserOperations delegate; | ||
private Function<ProxiedUserDetails,Boolean> condition; | ||
private Supplier<AuthorizationsListBase> authorizationsListBaseSupplier; | ||
|
||
private static final GenericResponse<String> EMPTY_RESPONSE = new GenericResponse<>(); | ||
|
||
public boolean isFiltered(ProxiedUserDetails principal) { | ||
if (!condition.apply(principal)) { | ||
if (log.isDebugEnabled()) { | ||
log.debug("Filter " + condition + " blocking " + principal.getName() + " from " + delegate + " user operations"); | ||
} | ||
return true; | ||
} else { | ||
if (log.isDebugEnabled()) { | ||
log.debug("Passing through filter " + condition + " for " + principal.getName() + " for " + delegate + " user operations"); | ||
} | ||
return false; | ||
} | ||
} | ||
|
||
@Override | ||
public AuthorizationsListBase listEffectiveAuthorizations(ProxiedUserDetails callerObject) throws AuthorizationException { | ||
assert (delegate != null); | ||
assert (condition != null); | ||
assert (authorizationsListBaseSupplier != null); | ||
|
||
if (!isFiltered(callerObject)) { | ||
return delegate.listEffectiveAuthorizations(callerObject); | ||
} else { | ||
AuthorizationsListBase response = authorizationsListBaseSupplier.get(); | ||
response.setUserAuths(callerObject.getPrimaryUser().getDn().subjectDN(), callerObject.getPrimaryUser().getDn().issuerDN(), Collections.EMPTY_LIST); | ||
return response; | ||
} | ||
} | ||
|
||
@Override | ||
public GenericResponse<String> flushCachedCredentials(ProxiedUserDetails callerObject) throws AuthorizationException { | ||
assert (delegate != null); | ||
assert (condition != null); | ||
assert (authorizationsListBaseSupplier != null); | ||
|
||
if (!isFiltered(callerObject)) { | ||
return delegate.flushCachedCredentials(callerObject); | ||
} else { | ||
return EMPTY_RESPONSE; | ||
} | ||
} | ||
|
||
public UserOperations getDelegate() { | ||
return delegate; | ||
} | ||
|
||
public void setDelegate(UserOperations delegate) { | ||
this.delegate = delegate; | ||
} | ||
|
||
public Function<ProxiedUserDetails,Boolean> getCondition() { | ||
return condition; | ||
} | ||
|
||
public void setCondition(Function<ProxiedUserDetails,Boolean> condition) { | ||
this.condition = condition; | ||
} | ||
|
||
public Supplier<AuthorizationsListBase> getAuthorizationsListBaseSupplier() { | ||
return authorizationsListBaseSupplier; | ||
} | ||
|
||
public void setAuthorizationsListBaseSupplier(Supplier<AuthorizationsListBase> authorizationsListBaseSupplier) { | ||
this.authorizationsListBaseSupplier = authorizationsListBaseSupplier; | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
src/main/java/datawave/security/authorization/UserOperations.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package datawave.security.authorization; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.function.Function; | ||
import java.util.stream.Collectors; | ||
|
||
import com.google.common.collect.HashMultimap; | ||
import com.google.common.collect.Multimap; | ||
|
||
import datawave.user.AuthorizationsListBase; | ||
import datawave.webservice.result.GenericResponse; | ||
|
||
/** | ||
* A user operations service is one that can pass calls off to another external user operations endpoint | ||
*/ | ||
public interface UserOperations { | ||
|
||
AuthorizationsListBase listEffectiveAuthorizations(ProxiedUserDetails callerObject) throws AuthorizationException; | ||
|
||
GenericResponse<String> flushCachedCredentials(ProxiedUserDetails callerObject) throws AuthorizationException; | ||
|
||
default <T extends ProxiedUserDetails> T getRemoteUser(T currentUser) throws AuthorizationException { | ||
// get the effective authorizations for this user | ||
AuthorizationsListBase auths = listEffectiveAuthorizations(currentUser); | ||
// create a new set of proxied users | ||
List<DatawaveUser> mappedUsers = new ArrayList<>(); | ||
Map<SubjectIssuerDNPair,DatawaveUser> localUsers = currentUser.getProxiedUsers().stream() | ||
.collect(Collectors.toMap(DatawaveUser::getDn, Function.identity(), (v1, v2) -> v2)); | ||
|
||
// create a mapped user for the primary user with the auths returned by listEffectiveAuthorizations | ||
SubjectIssuerDNPair primaryDn = SubjectIssuerDNPair.of(auths.getUserDn(), auths.getIssuerDn()); | ||
DatawaveUser localUser = localUsers.get(primaryDn); | ||
mappedUsers.add(new DatawaveUser(primaryDn, localUser.getUserType(), auths.getAllAuths(), auths.getAuthMapping().keySet(), | ||
toMultimap(auths.getAuthMapping()), System.currentTimeMillis())); | ||
// for each proxied user, create a new user with the auths returned by listEffectiveAuthorizations | ||
Map<AuthorizationsListBase.SubjectIssuerDNPair,Set<String>> authMap = auths.getAuths(); | ||
for (Map.Entry<AuthorizationsListBase.SubjectIssuerDNPair,Set<String>> entry : authMap.entrySet()) { | ||
SubjectIssuerDNPair pair = SubjectIssuerDNPair.of(entry.getKey().subjectDN, entry.getKey().issuerDN); | ||
if (!pair.equals(primaryDn)) { | ||
mappedUsers.add(new DatawaveUser(pair, DatawaveUser.UserType.SERVER, entry.getValue(), null, null, System.currentTimeMillis())); | ||
} | ||
} | ||
|
||
// return a proxied user details with the mapped users | ||
return currentUser.newInstance(mappedUsers); | ||
} | ||
|
||
static Multimap<String,String> toMultimap(Map<String,Collection<String>> map) { | ||
Multimap<String,String> multimap = HashMultimap.create(); | ||
map.forEach(multimap::putAll); | ||
return multimap; | ||
} | ||
|
||
} |