Druid basic authentication class composition config (#7789)

* Druid basic authentication class composition config.

* Added comments

* Reduced nulls

* Used noop implementations to get rid of null

* Added docs for no-op metadata storage updaters

* Fixed BasicAuthClassCompositionConfig javadoc

* Removed incorrect comments
This commit is contained in:
Eugene Sevastyanov 2019-06-06 16:51:37 +03:00 committed by Roman Leventov
parent 1de1a02e49
commit 080270283a
6 changed files with 493 additions and 56 deletions

View File

@ -0,0 +1,128 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.druid.security.basic;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Basic authentication storage/cache/resource handler config.
* BasicAuthClassCompositionConfig provides options to specify authenticator/authorizer classes of user/role managers,
* caches and notifiers. If a field in this class is non-null then the corresponding class is instantiated
* regardless of what type of Druid component runs it (see {@link BasicSecurityDruidModule}).
* Hence every Druid component might be a user/role manager and notify others by sending notifications.
* Every field must be a valid class name (appropriate for the corresponding goal) or null.
*/
public class BasicAuthClassCompositionConfig
{
@JsonProperty
private final String authenticatorMetadataStorageUpdater;
@JsonProperty
private final String authenticatorCacheManager;
@JsonProperty
private final String authenticatorResourceHandler;
@JsonProperty
private final String authenticatorCacheNotifier;
@JsonProperty
private final String authorizerMetadataStorageUpdater;
@JsonProperty
private final String authorizerCacheManager;
@JsonProperty
private final String authorizerResourceHandler;
@JsonProperty
private final String authorizerCacheNotifier;
@JsonCreator
public BasicAuthClassCompositionConfig(
@JsonProperty("authenticatorMetadataStorageUpdater") String authenticatorMetadataStorageUpdater,
@JsonProperty("authenticatorCacheManager") String authenticatorCacheManager,
@JsonProperty("authenticatorResourceHandler") String authenticatorResourceHandler,
@JsonProperty("authenticatorCacheNotifier") String authenticatorCacheNotifier,
@JsonProperty("authorizerMetadataStorageUpdater") String authorizerMetadataStorageUpdater,
@JsonProperty("authorizerCacheManager") String authorizerCacheManager,
@JsonProperty("authorizerResourceHandler") String authorizerResourceHandler,
@JsonProperty("authorizerCacheNotifier") String authorizerCacheNotifier
)
{
this.authenticatorMetadataStorageUpdater = authenticatorMetadataStorageUpdater;
this.authenticatorCacheManager = authenticatorCacheManager;
this.authenticatorResourceHandler = authenticatorResourceHandler;
this.authenticatorCacheNotifier = authenticatorCacheNotifier;
this.authorizerMetadataStorageUpdater = authorizerMetadataStorageUpdater;
this.authorizerCacheManager = authorizerCacheManager;
this.authorizerResourceHandler = authorizerResourceHandler;
this.authorizerCacheNotifier = authorizerCacheNotifier;
}
@JsonProperty
public String getAuthenticatorMetadataStorageUpdater()
{
return authenticatorMetadataStorageUpdater;
}
@JsonProperty
public String getAuthenticatorCacheManager()
{
return authenticatorCacheManager;
}
@JsonProperty
public String getAuthenticatorResourceHandler()
{
return authenticatorResourceHandler;
}
@JsonProperty
public String getAuthenticatorCacheNotifier()
{
return authenticatorCacheNotifier;
}
@JsonProperty
public String getAuthorizerMetadataStorageUpdater()
{
return authorizerMetadataStorageUpdater;
}
@JsonProperty
public String getAuthorizerCacheManager()
{
return authorizerCacheManager;
}
@JsonProperty
public String getAuthorizerResourceHandler()
{
return authorizerResourceHandler;
}
@JsonProperty
public String getAuthorizerCacheNotifier()
{
return authorizerCacheNotifier;
}
}

View File

@ -39,8 +39,10 @@ import org.apache.druid.security.basic.authentication.db.cache.BasicAuthenticato
import org.apache.druid.security.basic.authentication.db.cache.CoordinatorBasicAuthenticatorCacheNotifier; import org.apache.druid.security.basic.authentication.db.cache.CoordinatorBasicAuthenticatorCacheNotifier;
import org.apache.druid.security.basic.authentication.db.cache.CoordinatorPollingBasicAuthenticatorCacheManager; import org.apache.druid.security.basic.authentication.db.cache.CoordinatorPollingBasicAuthenticatorCacheManager;
import org.apache.druid.security.basic.authentication.db.cache.MetadataStoragePollingBasicAuthenticatorCacheManager; import org.apache.druid.security.basic.authentication.db.cache.MetadataStoragePollingBasicAuthenticatorCacheManager;
import org.apache.druid.security.basic.authentication.db.cache.NoopBasicAuthenticatorCacheNotifier;
import org.apache.druid.security.basic.authentication.db.updater.BasicAuthenticatorMetadataStorageUpdater; import org.apache.druid.security.basic.authentication.db.updater.BasicAuthenticatorMetadataStorageUpdater;
import org.apache.druid.security.basic.authentication.db.updater.CoordinatorBasicAuthenticatorMetadataStorageUpdater; import org.apache.druid.security.basic.authentication.db.updater.CoordinatorBasicAuthenticatorMetadataStorageUpdater;
import org.apache.druid.security.basic.authentication.db.updater.NoopBasicAuthenticatorMetadataStorageUpdater;
import org.apache.druid.security.basic.authentication.endpoint.BasicAuthenticatorResource; import org.apache.druid.security.basic.authentication.endpoint.BasicAuthenticatorResource;
import org.apache.druid.security.basic.authentication.endpoint.BasicAuthenticatorResourceHandler; import org.apache.druid.security.basic.authentication.endpoint.BasicAuthenticatorResourceHandler;
import org.apache.druid.security.basic.authentication.endpoint.CoordinatorBasicAuthenticatorResourceHandler; import org.apache.druid.security.basic.authentication.endpoint.CoordinatorBasicAuthenticatorResourceHandler;
@ -51,8 +53,10 @@ import org.apache.druid.security.basic.authorization.db.cache.BasicAuthorizerCac
import org.apache.druid.security.basic.authorization.db.cache.CoordinatorBasicAuthorizerCacheNotifier; import org.apache.druid.security.basic.authorization.db.cache.CoordinatorBasicAuthorizerCacheNotifier;
import org.apache.druid.security.basic.authorization.db.cache.CoordinatorPollingBasicAuthorizerCacheManager; import org.apache.druid.security.basic.authorization.db.cache.CoordinatorPollingBasicAuthorizerCacheManager;
import org.apache.druid.security.basic.authorization.db.cache.MetadataStoragePollingBasicAuthorizerCacheManager; import org.apache.druid.security.basic.authorization.db.cache.MetadataStoragePollingBasicAuthorizerCacheManager;
import org.apache.druid.security.basic.authorization.db.cache.NoopBasicAuthorizerCacheNotifier;
import org.apache.druid.security.basic.authorization.db.updater.BasicAuthorizerMetadataStorageUpdater; import org.apache.druid.security.basic.authorization.db.updater.BasicAuthorizerMetadataStorageUpdater;
import org.apache.druid.security.basic.authorization.db.updater.CoordinatorBasicAuthorizerMetadataStorageUpdater; import org.apache.druid.security.basic.authorization.db.updater.CoordinatorBasicAuthorizerMetadataStorageUpdater;
import org.apache.druid.security.basic.authorization.db.updater.NoopBasicAuthorizerMetadataStorageUpdater;
import org.apache.druid.security.basic.authorization.endpoint.BasicAuthorizerResource; import org.apache.druid.security.basic.authorization.endpoint.BasicAuthorizerResource;
import org.apache.druid.security.basic.authorization.endpoint.BasicAuthorizerResourceHandler; import org.apache.druid.security.basic.authorization.endpoint.BasicAuthorizerResourceHandler;
import org.apache.druid.security.basic.authorization.endpoint.CoordinatorBasicAuthorizerResourceHandler; import org.apache.druid.security.basic.authorization.endpoint.CoordinatorBasicAuthorizerResourceHandler;
@ -62,10 +66,12 @@ import java.util.List;
public class BasicSecurityDruidModule implements DruidModule public class BasicSecurityDruidModule implements DruidModule
{ {
@Override @Override
public void configure(Binder binder) public void configure(Binder binder)
{ {
JsonConfigProvider.bind(binder, "druid.auth.basic.common", BasicAuthCommonCacheConfig.class); JsonConfigProvider.bind(binder, "druid.auth.basic.common", BasicAuthCommonCacheConfig.class);
JsonConfigProvider.bind(binder, "druid.auth.basic.composition", BasicAuthClassCompositionConfig.class);
LifecycleModule.register(binder, BasicAuthenticatorMetadataStorageUpdater.class); LifecycleModule.register(binder, BasicAuthenticatorMetadataStorageUpdater.class);
LifecycleModule.register(binder, BasicAuthorizerMetadataStorageUpdater.class); LifecycleModule.register(binder, BasicAuthorizerMetadataStorageUpdater.class);
@ -76,84 +82,124 @@ public class BasicSecurityDruidModule implements DruidModule
Jerseys.addResource(binder, BasicAuthorizerResource.class); Jerseys.addResource(binder, BasicAuthorizerResource.class);
} }
@Provides @LazySingleton @Provides
public static BasicAuthenticatorMetadataStorageUpdater createAuthenticatorStorageUpdater(final Injector injector) @LazySingleton
public static BasicAuthenticatorMetadataStorageUpdater createAuthenticatorStorageUpdater(
final Injector injector,
BasicAuthClassCompositionConfig config
) throws ClassNotFoundException
{ {
if (isCoordinator(injector)) { return getInstance(
return injector.getInstance(CoordinatorBasicAuthenticatorMetadataStorageUpdater.class); injector,
} else { config.getAuthenticatorMetadataStorageUpdater(),
return null; CoordinatorBasicAuthenticatorMetadataStorageUpdater.class,
} NoopBasicAuthenticatorMetadataStorageUpdater.class
);
} }
@Provides @LazySingleton @Provides
public static BasicAuthenticatorCacheManager createAuthenticatorCacheManager(final Injector injector) @LazySingleton
public static BasicAuthenticatorCacheManager createAuthenticatorCacheManager(
final Injector injector,
BasicAuthClassCompositionConfig config
) throws ClassNotFoundException
{ {
if (isCoordinator(injector)) { return getInstance(
return injector.getInstance(MetadataStoragePollingBasicAuthenticatorCacheManager.class); injector,
} else { config.getAuthenticatorCacheManager(),
return injector.getInstance(CoordinatorPollingBasicAuthenticatorCacheManager.class); MetadataStoragePollingBasicAuthenticatorCacheManager.class,
} CoordinatorPollingBasicAuthenticatorCacheManager.class
);
} }
@Provides @LazySingleton @Provides
public static BasicAuthenticatorResourceHandler createAuthenticatorResourceHandler(final Injector injector) @LazySingleton
public static BasicAuthenticatorResourceHandler createAuthenticatorResourceHandler(
final Injector injector,
BasicAuthClassCompositionConfig config
) throws ClassNotFoundException
{ {
if (isCoordinator(injector)) { return getInstance(
return injector.getInstance(CoordinatorBasicAuthenticatorResourceHandler.class); injector,
} else { config.getAuthenticatorResourceHandler(),
return injector.getInstance(DefaultBasicAuthenticatorResourceHandler.class); CoordinatorBasicAuthenticatorResourceHandler.class,
} DefaultBasicAuthenticatorResourceHandler.class
);
} }
@Provides @LazySingleton @Provides
public static BasicAuthenticatorCacheNotifier createAuthenticatorCacheNotifier(final Injector injector) @LazySingleton
public static BasicAuthenticatorCacheNotifier createAuthenticatorCacheNotifier(
final Injector injector,
BasicAuthClassCompositionConfig config
) throws ClassNotFoundException
{ {
if (isCoordinator(injector)) { return getInstance(
return injector.getInstance(CoordinatorBasicAuthenticatorCacheNotifier.class); injector,
} else { config.getAuthenticatorCacheNotifier(),
return null; CoordinatorBasicAuthenticatorCacheNotifier.class,
} NoopBasicAuthenticatorCacheNotifier.class
);
} }
@Provides @LazySingleton @Provides
public static BasicAuthorizerMetadataStorageUpdater createAuthorizerStorageUpdater(final Injector injector) @LazySingleton
public static BasicAuthorizerMetadataStorageUpdater createAuthorizerStorageUpdater(
final Injector injector,
BasicAuthClassCompositionConfig config
) throws ClassNotFoundException
{ {
if (isCoordinator(injector)) { return getInstance(
return injector.getInstance(CoordinatorBasicAuthorizerMetadataStorageUpdater.class); injector,
} else { config.getAuthorizerMetadataStorageUpdater(),
return null; CoordinatorBasicAuthorizerMetadataStorageUpdater.class,
} NoopBasicAuthorizerMetadataStorageUpdater.class
);
} }
@Provides @LazySingleton @Provides
public static BasicAuthorizerCacheManager createAuthorizerCacheManager(final Injector injector) @LazySingleton
public static BasicAuthorizerCacheManager createAuthorizerCacheManager(
final Injector injector,
BasicAuthClassCompositionConfig config
) throws ClassNotFoundException
{ {
if (isCoordinator(injector)) { return getInstance(
return injector.getInstance(MetadataStoragePollingBasicAuthorizerCacheManager.class); injector,
} else { config.getAuthorizerCacheManager(),
return injector.getInstance(CoordinatorPollingBasicAuthorizerCacheManager.class); MetadataStoragePollingBasicAuthorizerCacheManager.class,
} CoordinatorPollingBasicAuthorizerCacheManager.class
);
} }
@Provides @LazySingleton @Provides
public static BasicAuthorizerResourceHandler createAuthorizerResourceHandler(final Injector injector) @LazySingleton
public static BasicAuthorizerResourceHandler createAuthorizerResourceHandler(
final Injector injector,
BasicAuthClassCompositionConfig config
) throws ClassNotFoundException
{ {
if (isCoordinator(injector)) { return getInstance(
return injector.getInstance(CoordinatorBasicAuthorizerResourceHandler.class); injector,
} else { config.getAuthorizerResourceHandler(),
return injector.getInstance(DefaultBasicAuthorizerResourceHandler.class); CoordinatorBasicAuthorizerResourceHandler.class,
} DefaultBasicAuthorizerResourceHandler.class
);
} }
@Provides @LazySingleton @Provides
public static BasicAuthorizerCacheNotifier createAuthorizerCacheNotifier(final Injector injector) @LazySingleton
public static BasicAuthorizerCacheNotifier createAuthorizerCacheNotifier(
final Injector injector,
BasicAuthClassCompositionConfig config
) throws ClassNotFoundException
{ {
if (isCoordinator(injector)) { return getInstance(
return injector.getInstance(CoordinatorBasicAuthorizerCacheNotifier.class); injector,
} else { config.getAuthorizerCacheNotifier(),
return null; CoordinatorBasicAuthorizerCacheNotifier.class,
} NoopBasicAuthorizerCacheNotifier.class
);
} }
@Override @Override
@ -168,6 +214,29 @@ public class BasicSecurityDruidModule implements DruidModule
); );
} }
/**
* Returns the instance provided either by a config property or coordinator-run class or default class.
* The order of check corresponds to the order of method params.
*/
private static <T> T getInstance(
Injector injector,
String configClassName,
Class<? extends T> classRunByCoordinator,
Class<? extends T> defaultClass
) throws ClassNotFoundException
{
if (configClassName != null) {
// ClassCastException is thrown in case of a mismatch, configuration fix is required.
@SuppressWarnings("unchecked")
final T instance = (T) injector.getInstance(Class.forName(configClassName));
return instance;
}
if (isCoordinator(injector)) {
return injector.getInstance(classRunByCoordinator);
}
return injector.getInstance(defaultClass);
}
private static boolean isCoordinator(Injector injector) private static boolean isCoordinator(Injector injector)
{ {
final String serviceName; final String serviceName;

View File

@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.druid.security.basic.authentication.db.cache;
/**
* Noop basic authenticator cache notifier.
* No notification is sent on user udpate.
* Might be used as a config option to override default authenticator cache notifier.
*/
public class NoopBasicAuthenticatorCacheNotifier implements BasicAuthenticatorCacheNotifier
{
@Override
public void addUpdate(String updatedAuthenticatorPrefix, byte[] updatedUserMap)
{
// Do nothing as this is a noop implementation
}
}

View File

@ -0,0 +1,73 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.druid.security.basic.authentication.db.updater;
import org.apache.druid.security.basic.authentication.entity.BasicAuthenticatorCredentialUpdate;
import org.apache.druid.security.basic.authentication.entity.BasicAuthenticatorUser;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Map;
/**
* Empty implementation of {@link BasicAuthenticatorMetadataStorageUpdater}.
* Void methods do nothing, other return empty maps or empty arrays depending on the return type.
*/
public class NoopBasicAuthenticatorMetadataStorageUpdater implements BasicAuthenticatorMetadataStorageUpdater
{
@Override
public void createUser(String prefix, String userName)
{
}
@Override
public void deleteUser(String prefix, String userName)
{
}
@Override
public void setUserCredentials(String prefix, String userName, BasicAuthenticatorCredentialUpdate update)
{
}
@Nullable
@Override
public Map<String, BasicAuthenticatorUser> getCachedUserMap(String prefix)
{
return Collections.emptyMap();
}
@Override
public byte[] getCachedSerializedUserMap(String prefix)
{
return new byte[0];
}
@Override
public byte[] getCurrentUserMapBytes(String prefix)
{
return new byte[0];
}
@Override
public void refreshAllNotification()
{
}
}

View File

@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.druid.security.basic.authorization.db.cache;
/**
* Noop basic authorizer cache notifier.
* No notification is sent on user/role udpate.
* Might be used as a config option to override default authorizer cache notifier.
*/
public class NoopBasicAuthorizerCacheNotifier implements BasicAuthorizerCacheNotifier
{
@Override
public void addUpdate(String authorizerPrefix, byte[] userAndRoleMap)
{
// Do nothing as this is a noop implementation
}
}

View File

@ -0,0 +1,99 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.druid.security.basic.authorization.db.updater;
import org.apache.druid.security.basic.authorization.entity.BasicAuthorizerRole;
import org.apache.druid.security.basic.authorization.entity.BasicAuthorizerUser;
import org.apache.druid.server.security.ResourceAction;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Empty implementation of {@link BasicAuthorizerMetadataStorageUpdater}.
* Void methods do nothing, other return empty maps or empty arrays depending on the return type.
*/
public class NoopBasicAuthorizerMetadataStorageUpdater implements BasicAuthorizerMetadataStorageUpdater
{
@Override
public void createUser(String prefix, String userName)
{
}
@Override
public void deleteUser(String prefix, String userName)
{
}
@Override
public void createRole(String prefix, String roleName)
{
}
@Override
public void deleteRole(String prefix, String roleName)
{
}
@Override
public void assignRole(String prefix, String userName, String roleName)
{
}
@Override
public void unassignRole(String prefix, String userName, String roleName)
{
}
@Override
public void setPermissions(String prefix, String roleName, List<ResourceAction> permissions)
{
}
@Override
public Map<String, BasicAuthorizerUser> getCachedUserMap(String prefix)
{
return Collections.emptyMap();
}
@Override
public Map<String, BasicAuthorizerRole> getCachedRoleMap(String prefix)
{
return Collections.emptyMap();
}
@Override
public byte[] getCurrentUserMapBytes(String prefix)
{
return new byte[0];
}
@Override
public byte[] getCurrentRoleMapBytes(String prefix)
{
return new byte[0];
}
@Override
public void refreshAllNotification()
{
}
}