package org.ovirt.engine.core.sso.search; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.ovirt.engine.api.extensions.Base; import org.ovirt.engine.api.extensions.ExtMap; import org.ovirt.engine.api.extensions.aaa.Authn; import org.ovirt.engine.api.extensions.aaa.Authz; import org.ovirt.engine.core.extensions.mgr.ExtensionProxy; public class AuthzUtils { @FunctionalInterface private interface QueryResultHandler { boolean handle(Collection<ExtMap> queryResults); } private static final int QUERIES_RESULTS_LIMIT = 1000; private static final int PAGE_SIZE = 500; public static String getName(ExtensionProxy proxy) { return proxy.getContext().get(Base.ContextKeys.INSTANCE_NAME); } public static boolean supportsPasswordAuthentication(ExtensionProxy proxy) { return (proxy.getContext().<Long>get(Authn.ContextKeys.CAPABILITIES, 0L) & Authn.Capabilities.AUTHENTICATE_PASSWORD) != 0; } public static ExtMap fetchPrincipalRecord( final ExtensionProxy extension, String principal, boolean resolveGroups, boolean resolveGroupsRecursive) { return fetchPrincipalRecordImpl( extension, new ExtMap().mput( Authz.InvokeKeys.PRINCIPAL, principal ), resolveGroups, resolveGroupsRecursive ); } private static ExtMap fetchPrincipalRecordImpl( final ExtensionProxy extension, ExtMap m, boolean resolveGroups, boolean resolveGroupsRecursive) { ExtMap ret = null; ExtMap output = extension.invoke( m.mput( Base.InvokeKeys.COMMAND, Authz.InvokeCommands.FETCH_PRINCIPAL_RECORD ).mput( Authz.InvokeKeys.QUERY_FLAGS, (resolveGroups ? Authz.QueryFlags.RESOLVE_GROUPS : 0) | (resolveGroupsRecursive ? Authz.QueryFlags.RESOLVE_GROUPS_RECURSIVE : 0) )); if (output.<Integer>get(Authz.InvokeKeys.STATUS) == Authz.Status.SUCCESS) { ret = output.get(Authz.InvokeKeys.PRINCIPAL_RECORD); } return ret; } public static Collection<ExtMap> queryPrincipalRecords( final ExtensionProxy extension, final String namespace, final ExtMap filter, boolean groupsResolving, boolean groupsResolvingRecursive) { ExtMap inputMap = new ExtMap().mput( Authz.InvokeKeys.QUERY_ENTITY, Authz.QueryEntity.PRINCIPAL ).mput( Authz.InvokeKeys.QUERY_FLAGS, queryFlagValue(groupsResolving, groupsResolvingRecursive) ).mput( Authz.InvokeKeys.QUERY_FILTER, filter ).mput( Authz.InvokeKeys.NAMESPACE, namespace ); return populateRecords( extension, namespace, inputMap); } public static Collection<ExtMap> queryGroupRecords( final ExtensionProxy extension, final String namespace, final ExtMap filter, boolean groupsResolving, boolean groupsResolvingRecursive) { ExtMap inputMap = new ExtMap().mput( Authz.InvokeKeys.QUERY_ENTITY, Authz.QueryEntity.GROUP ).mput( Authz.InvokeKeys.QUERY_FLAGS, queryFlagValue(groupsResolving, groupsResolvingRecursive) ).mput( Authz.InvokeKeys.QUERY_FILTER, filter ).mput( Authz.InvokeKeys.NAMESPACE, namespace ); return populateRecords( extension, namespace, inputMap); } public static Collection<ExtMap> populateRecords( final ExtensionProxy extension, final String namespace, final ExtMap input) { final Collection<ExtMap> records = new ArrayList<>(); queryImpl(extension, namespace, input, queryResults -> { boolean result = true; for (ExtMap queryResult : queryResults) { if (records.size() < QUERIES_RESULTS_LIMIT) { records.add(queryResult); } else { result = false; break; } } return result; }); return records; } private static void queryImpl( final ExtensionProxy extension, final String namespace, final ExtMap input, final QueryResultHandler handler) { Object opaque = extension.invoke( new ExtMap().mput( Base.InvokeKeys.COMMAND, Authz.InvokeCommands.QUERY_OPEN ).mput( Authz.InvokeKeys.NAMESPACE, namespace ).mput( input ) ).get(Authz.InvokeKeys.QUERY_OPAQUE); Collection<ExtMap> result = null; try { do { result = extension.invoke( new ExtMap().mput( Base.InvokeKeys.COMMAND, Authz.InvokeCommands.QUERY_EXECUTE ).mput( Authz.InvokeKeys.QUERY_OPAQUE, opaque ).mput( Authz.InvokeKeys.PAGE_SIZE, PAGE_SIZE ) ).get(Authz.InvokeKeys.QUERY_RESULT); } while (result != null && handler.handle(result)); } finally { extension.invoke( new ExtMap().mput( Base.InvokeKeys.COMMAND, Authz.InvokeCommands.QUERY_CLOSE ).mput( Authz.InvokeKeys.QUERY_OPAQUE, opaque ) ); } } public static List<ExtMap> findPrincipalsByIds( final ExtensionProxy extension, final String namespace, final Collection<String> ids, final boolean groupsResolving, final boolean groupsResolvingRecursive) { List<ExtMap> results = new ArrayList<>(); SearchParsingUtils.getIdsBatches(extension.getContext(), ids).forEach( batch -> results.addAll( queryPrincipalRecords( extension, namespace, SearchParsingUtils.generateQueryMap( batch, Authz.QueryEntity.PRINCIPAL ), groupsResolving, groupsResolvingRecursive ) )); return results; } public static Collection<ExtMap> findGroupRecordsByIds( final ExtensionProxy extension, final String namespace, final Collection<String> ids, final boolean groupsResolving, final boolean groupsResolvingRecursive) { Collection<ExtMap> results = new ArrayList<>(); SearchParsingUtils.getIdsBatches(extension.getContext(), ids).forEach( batch -> results.addAll( queryGroupRecords( extension, namespace, SearchParsingUtils.generateQueryMap( batch, Authz.QueryEntity.GROUP ), groupsResolving, groupsResolvingRecursive))); return results; } private static int queryFlagValue(boolean resolveGroups, boolean resolveGroupsRecursive) { int result = 0; if (resolveGroups) { result |= Authz.QueryFlags.RESOLVE_GROUPS; } if (resolveGroupsRecursive) { result |= Authz.QueryFlags.RESOLVE_GROUPS_RECURSIVE | Authz.QueryFlags.RESOLVE_GROUPS; } return result; } }