Ovirt程序员

【Ovirt 笔记】engine 用户扩展管理分析与整理

2018-06-13  本文已影响18人  58bc06151329

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

分析整理的版本为 Ovirt 4.2.3 版本。

1. 用户与角色

2. 本地用户域

2.1 创建 aaa-jdbc 配置文件

@util.export
def createPlugins(context):
    aaa.Plugin(context=context)
    aaainternal.Plugin(context=context)
......
self.environment[otopicons.CoreEnv.MAIN_TRANSACTION].append(
            filetransaction.FileTransaction(
                name=(
                    os.path.join(
                        oenginecons.FileLocations.OVIRT_ENGINE_EXTENSIONS_DIR,
                        '%s-authn.properties' % profile
                    )
                ),
                mode=0o600,
                owner=self.environment[osetupcons.SystemEnv.USER_ENGINE],
                enforcePermissions=True,
                content=(
                    'ovirt.engine.extension.name = internal-authn\n'
                    'ovirt.engine.extension.bindings.method = jbossmodule\n'

                    'ovirt.engine.extension.binding.jbossmodule.module = '
                    'org.ovirt.engine.extensions.builtin\n'

                    'ovirt.engine.extension.binding.jbossmodule.class = '
                    'org.ovirt.engine.extensions.aaa.builtin.internal.'
                    'InternalAuthn\n'

                    'ovirt.engine.extension.provides = '
                    'org.ovirt.engine.api.extensions.aaa.Authn\n'

                    'ovirt.engine.aaa.authn.profile.name = {profile}\n'
                    'ovirt.engine.aaa.authn.authz.plugin = {authzName}\n'
                    'config.authn.user.name = {admin_user}\n'
                    'config.authn.user.password = {pbe}\n'
[root@rhvm extensions.d]# pwd
/etc/ovirt-engine/extensions.d
[root@rhvm extensions.d]# ls
internal-authn.properties  internal-authz.properties
[root@rhvm extensions.d]# cat internal-authn.properties 
ovirt.engine.extension.name = internal-authn
ovirt.engine.extension.bindings.method = jbossmodule
ovirt.engine.extension.binding.jbossmodule.module = org.ovirt.engine.extensions.builtin
ovirt.engine.extension.binding.jbossmodule.class = org.ovirt.engine.extensions.aaa.builtin.internal.InternalAuthn
ovirt.engine.extension.provides = org.ovirt.engine.api.extensions.aaa.Authn
ovirt.engine.aaa.authn.profile.name = internal
ovirt.engine.aaa.authn.authz.plugin = internal-authz
参数 说明
ovirt.engine.extension.name 扩展模块的名称为 internal-authn。
ovirt.engine.extension.bindings.method 扩展的方法,使用了 Jboss 的 module。
ovirt.engine.extension.binding.jbossmodule.module 加载的 Jboss module。
ovirt.engine.extension.binding.jbossmodule.class 加载 Jboss module 的 class 类。
ovirt.engine.extension.provides 使用的供应者类(代理)。
ovirt.engine.aaa.authn.profile.name 域名。
ovirt.engine.aaa.authn.authz.plugin 依赖的模块。
config.datasource.file 数据库相关配置文件路径。
ovirt.engine.extension.enabled 是否启用,默认为 true。
[root@rhvm extensions.d]# cat internal-authz.properties 
ovirt.engine.extension.name = internal-authz
ovirt.engine.extension.bindings.method = jbossmodule
ovirt.engine.extension.binding.jbossmodule.module = org.ovirt.engine.extensions.builtin
ovirt.engine.extension.binding.jbossmodule.class = org.ovirt.engine.extensions.aaa.builtin.internal.InternalAuthz
ovirt.engine.extension.provides = org.ovirt.engine.api.extensions.aaa.Authz
参数 说明
ovirt.engine.extension.name 扩展模块的名称 internal-authz。
ovirt.engine.extension.bindings.method 扩展的方法,使用了 Jboss 的 module。
ovirt.engine.extension.binding.jbossmodule.module 加载的 Jboss module。
ovirt.engine.extension.binding.jbossmodule.class 加载 Jboss module 的 class 类。
ovirt.engine.extension.provides 使用的供应者类(代理)。
config.datasource.file 数据库相关配置文件路径。
ovirt.engine.extension.enabled 是否启用,默认为 true。

2.2 加载 aaa-jdbc 配置信息

EngineExtensionsManager.getInstance().engineInitialize();
[root@rhvm extensions.d]# cat /usr/share/ovirt-engine/services/ovirt-engine/ovirt-engine.conf | grep ENGINE_EXTENSION_PATH
ENGINE_EXTENSION_PATH="${ENGINE_USR}/extensions.d:${ENGINE_ETC}/extensions.d"
for (File directory : EngineLocalConfig.getInstance().getExtensionsDirectories()) {
            if (!directory.exists()) {
                log.warn("The directory '{}' cotaning configuration files does not exist.",
                        directory.getAbsolutePath());
            } else {

                // The order of the files inside the directory is relevant, as the objects are created in
                // the same order
                // that
                // the files are processed, so it is better to sort them so that objects will always be
                // created in the
                // same
                // order regardless of how the filesystem decides to store the entries of the directory:
                File[] files = directory.listFiles();
                if (files != null) {
                    sort(files);
                    for (File file : files) {
                        if (file.getName().endsWith(".properties")) {
                            try {
                                load(file);
                            } catch (Exception ex) {
                                log.error("Could not load extension based on configuration file '{}'. Please check the configuration file is valid. Exception message is: {}",
                                        file.getAbsolutePath(),
                                        ex.getMessage());
                                log.debug("", ex);
                            }
                        }
                    }
                }
            }
}
public String load(File file) {
        try (
            InputStream is = new FileInputStream(file);
            Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)
        ) {
            Properties props = new Properties();
            props.load(reader);
            return loadImpl(props, file);
        } catch (IOException exception) {
            throw new ConfigurationException(String.format("Can't load object configuration file '%1$s': %2$s",
                    file.getAbsolutePath(), exception.getMessage()), exception);
        }
}
ExtensionEntry entry = new ExtensionEntry(props, confFile);
......
entry.extension = loadExtension(props);
            entry.extension.getContext().mput(
                    Base.ContextKeys.GLOBAL_CONTEXT,
                    globalContext
                    ).mput(
                            TRACE_LOG_CONTEXT_KEY,
                            traceLog
                    ).mput(
                            Base.ContextKeys.INTERFACE_VERSION_MIN,
                            0
                    ).mput(
                            Base.ContextKeys.INTERFACE_VERSION_MAX,
                            Base.INTERFACE_VERSION_CURRENT
                    ).mput(
                            Base.ContextKeys.LOCALE,
                            Locale.getDefault().toString()
                    ).mput(
                            Base.ContextKeys.CONFIGURATION_FILE,
                            entry.file == null ? null : entry.file.getAbsolutePath()
                    ).mput(
                            Base.ContextKeys.CONFIGURATION,
                            props
                    ).mput(
                            Base.ContextKeys.CONFIGURATION_SENSITIVE_KEYS,
                            splitString(props.getProperty(Base.ConfigKeys.SENSITIVE_KEYS, ""))
                    ).mput(
                            Base.ContextKeys.INSTANCE_NAME,
                            entry.name
                    ).mput(
                            Base.ContextKeys.PROVIDES,
                            splitString(props.getProperty(Base.ConfigKeys.PROVIDES, ""))
                    );
BindingsLoader loader = bindingsLoaders.get(props.getProperty(Base.ConfigKeys.BINDINGS_METHOD));
......
public ExtensionProxy load(Properties props) throws Exception {
            Module module = loadModule(
                props.getProperty(Base.ConfigKeys.BINDINGS_JBOSSMODULE_MODULE)
            );

            return new ExtensionProxy(
                module.getClassLoader(),
                lookupService(
                    module,
                    Extension.class,
                    props.getProperty(Base.ConfigKeys.BINDINGS_JBOSSMODULE_CLASS)
                ).newInstance()
            );
}

2.3 使用默认的本地用户域支持

ExtMap outputMap = profile.authn.invoke(new ExtMap().mput(
                            Base.InvokeKeys.COMMAND,
                            Authn.InvokeCommands.AUTHENTICATE_CREDENTIALS
                    ).mput(
                            Authn.InvokeKeys.USER,
                            user
                    ).mput(
                            Authn.InvokeKeys.CREDENTIALS,
                            credentials.getPassword()
                    )
public void invoke(ExtMap input, ExtMap output) {
        try {
            if (input.get(Base.InvokeKeys.COMMAND).equals(Base.InvokeCommands.LOAD)) {
                doLoad(input);
            } else if (input.get(Base.InvokeKeys.COMMAND).equals(Base.InvokeCommands.INITIALIZE)) {
                // Do nothing
            } else if (input.get(Base.InvokeKeys.COMMAND).equals(Authn.InvokeCommands.AUTHENTICATE_CREDENTIALS)) {
                doAuthenticate(input, output);
            } else {
                output.put(Base.InvokeKeys.RESULT, Base.InvokeResult.UNSUPPORTED);
            }
            output.putIfAbsent(Base.InvokeKeys.RESULT, Base.InvokeResult.SUCCESS);
        } catch (Exception ex) {
            output.mput(Base.InvokeKeys.RESULT, Base.InvokeResult.FAILED).
                   mput(Base.InvokeKeys.MESSAGE, ex.getMessage());
        }

}
private void doAuthenticate(ExtMap input, ExtMap output) throws IOException, GeneralSecurityException {
        output.put(Authn.InvokeKeys.PRINCIPAL, input.get(Authn.InvokeKeys.USER));
        if (
            input.get(Authn.InvokeKeys.USER).equals(adminUser) &&
            EnvelopePBE.check(adminPassword, input.get(Authn.InvokeKeys.CREDENTIALS))
        ) {
            output.mput(
                    Authn.InvokeKeys.RESULT,
                    Authn.AuthResult.SUCCESS
                    ).mput(
                            Authn.InvokeKeys.AUTH_RECORD,
                            new ExtMap().mput(
                                    Authn.AuthRecord.PRINCIPAL,
                                    adminUser
                                    )
                    );
        } else {
            output.put(Authn.InvokeKeys.RESULT, Authn.AuthResult.CREDENTIALS_INVALID);
        }
}
......
Properties config = context.get(Base.ContextKeys.CONFIGURATION);
adminUser = config.getProperty("config.authn.user.name", "admin");
adminPassword = config.getProperty("config.authn.user.password");

2.4 使用扩展的本地用户域支持

@util.export
def createPlugins(context):
    aaa.Plugin(context=context)
    ......
    aaajdbc.Plugin(context=context)
......
yum install ovirt-engine-extension-aaa-jdbc
[root@rhvm extensions.d]# cat internal-authn.properties
ovirt.engine.extension.name = internal-authn
ovirt.engine.extension.bindings.method = jbossmodule
ovirt.engine.extension.binding.jbossmodule.module = org.ovirt.engine.extension.aaa.jdbc
ovirt.engine.extension.binding.jbossmodule.class = org.ovirt.engine.extension.aaa.jdbc.binding.api.AuthnExtension
ovirt.engine.extension.provides = org.ovirt.engine.api.extensions.aaa.Authn
ovirt.engine.aaa.authn.profile.name = internal
ovirt.engine.aaa.authn.authz.plugin = internal-authz
config.datasource.file = /etc/ovirt-engine/aaa/internal.properties
[root@rhvm extensions.d]# cat internal-authz.properties
ovirt.engine.extension.name = internal-authz
ovirt.engine.extension.bindings.method = jbossmodule
ovirt.engine.extension.binding.jbossmodule.module = org.ovirt.engine.extension.aaa.jdbc
ovirt.engine.extension.binding.jbossmodule.class = org.ovirt.engine.extension.aaa.jdbc.binding.api.AuthzExtension
ovirt.engine.extension.provides = org.ovirt.engine.api.extensions.aaa.Authz
config.datasource.file = /etc/ovirt-engine/aaa/internal.properties
public void invoke(ExtMap input, ExtMap output) {
        try {
            if (tasks != null) {
                tasks.execute();
            }
            if (input.get(Base.InvokeKeys.COMMAND).equals(Base.InvokeCommands.LOAD)) {
                doLoad(input);
            } else if (input.get(Base.InvokeKeys.COMMAND).equals(Base.InvokeCommands.INITIALIZE)) {
                doInit(input);
            } else if (input.get(Base.InvokeKeys.COMMAND).equals(Base.InvokeCommands.TERMINATE)) {
                // Nothing to do.
            } else if (
                (input.get(Base.InvokeKeys.COMMAND).equals(Authn.InvokeCommands.AUTHENTICATE_CREDENTIALS)) ||
                (input.get(Base.InvokeKeys.COMMAND).equals(Authn.InvokeCommands.CREDENTIALS_CHANGE))
            ) {
                doAuth(input, output);
            } else {
                output.put(Base.InvokeKeys.RESULT, Base.InvokeResult.UNSUPPORTED);
                throw new IllegalArgumentException("unsupported:" + input.get(Base.InvokeKeys.COMMAND));
            }
            output.mput(Base.InvokeKeys.RESULT, Base.InvokeResult.SUCCESS);
        } catch (Throwable e) {
            LOG.error(
                "Unexpected Exception invoking: {}",
                input.<ExtUUID>get(Base.InvokeKeys.COMMAND)
            );
            LOG.debug(
                "Exception:",
                e
            );
            output.putIfAbsent(Base.InvokeKeys.RESULT, Base.InvokeResult.FAILED);
            output.put(Base.InvokeKeys.MESSAGE, e.getMessage());
        }
}
Authentication.AuthResponse response = authentication.doAuth(
            input.get(Authn.InvokeKeys.USER, String.class),
            input.get(Authn.InvokeKeys.CREDENTIALS, String.class),
            input.get(Base.InvokeKeys.COMMAND).equals(Authn.InvokeCommands.CREDENTIALS_CHANGE),
            input.get(Authn.InvokeKeys.CREDENTIALS_NEW, String.class)
);
Schema.get(
                new ExtMap().mput(Schema.InvokeKeys.ENTITY, Schema.Entities.USER)
                .mput(Schema.InvokeKeys.DATA_SOURCE, ds)
                .mput(Schema.InvokeKeys.SETTINGS_RESULT, settings)
                .mput(
                    Schema.InvokeKeys.ENTITY_KEYS,
                    new ExtMap().mput(
                        Schema.UserIdentifiers.USERNAME,
                        subject
                    )
                )
            ).get(
                Schema.InvokeKeys.USER_RESULT,
                Schema.User.class
            );
if (input.get(InvokeKeys.ENTITY, ExtUUID.class).equals(Entities.USER)) {
            ret.mput(
                InvokeKeys.USER_RESULT,
                new Sql.Query(
                    Formatter.format(
                        GET_USER,
                        generateWhere(input.get(InvokeKeys.ENTITY_KEYS, ExtMap.class))
                    )
                ).asResults(
                    ds,
                    USER_RESOLVER,
                    input.get(InvokeKeys.SETTINGS_RESULT, ExtMap.class)
                )
            );
config.datasource.file = /etc/ovirt-engine/aaa/internal.properties
[root@rhvm extensions.d]# cat /etc/ovirt-engine/aaa/internal.properties
config.datasource.jdbcurl=jdbc:postgresql://localhost:5432/engine?sslfactory=org.postgresql.ssl.NonValidatingFactory
config.datasource.dbuser=engine
config.datasource.dbpassword=Au1qXqSMx3nDRxCQD94RVq
config.datasource.jdbcdriver=org.postgresql.Driver
config.datasource.schemaname=aaa_jdbc
public static class Settings {
        /**
         * Authentication related
         */
        public static final ExtKey PASSWORD_HISTORY_LIMIT = new ExtKey("", Integer.class, "e843bc2a-0878-4b6f-9be3-32e83169fb7c");
        public static final ExtKey LOCK_MINUTES = new ExtKey("", Integer.class, "78b5138a-d52b-464d-a2a7-5fed55bdf7b3");
        public static final ExtKey PRESENT_WELCOME_MESSAGE = new ExtKey("", Boolean.class, "0ae5affd-15e5-4bb1-9910-f091b64b7197");
        public static final ExtKey MESSAGE_SEPARATOR = new ExtKey("", String.class, "ecf6d62a-10f8-4fad-b401-75c9d0788955");
        public static final ExtKey MESSAGE_OF_THE_DAY = new ExtKey("", String.class, "df496823-6814-4720-a302-c723f629f847");
        public static final ExtKey PASSWORD_EXPIRATION_DAYS = new ExtKey("", Integer.class, "dc3e2fb4-cbcc-4f5c-9b06-5db9ec534aa8");
......
private static class SettingsResolver implements Sql.ResultsResolver<ExtMap> {
        @Override
        public ExtMap resolve(ResultSet rs, ExtMap ctx) throws SQLException {
            ExtMap settings = new ExtMap();
            ExtMap descriptions = new ExtMap();
            UUID uuid;
            ExtKey key = null;
            String value = null;
            try {
                while (rs.next()) {
                    uuid = UUID.fromString(rs.getString("uuid"));
                    key = SETTING_KEYS.get(uuid);
                    value = rs.getString("value");
                    if (key != null) {
                        settings.put(
                            new ExtKey(rs.getString("name"), key.getType(), key.getUuid().getUuid().toString()),
                            key.getType().getConstructor(java.lang.String.class).newInstance(value)
                        );
                        descriptions.put(
                            new ExtKey(rs.getString("name"), String.class, key.getUuid().getUuid().toString()),
                            rs.getString("description")
                        );
                    } else {
                        throw new RuntimeException("key for " + uuid + " not found");
                    }
                }
            } catch ( NoSuchMethodException|InvocationTargetException|InstantiationException|IllegalAccessException e) {
                throw new RuntimeException(
                    Formatter.format(
                        "Could not convert setting to expected type. value: {} requested type: {}",
                        value,
                        key.getType()
                    ),
                    e
                );
            }
            return settings.mput(Settings.SETTING_DESCRIPTIONS, descriptions);
        }
}

3. 外部用户域

yum install ovirt-engine-extension-aaa-ldap
[root@rhvm extensions.d]# cat ad-authz.properties
ovirt.engine.extension.name = ad-authz
ovirt.engine.extension.bindings.method = jbossmodule
ovirt.engine.extension.binding.jbossmodule.module =
org.ovirt.engine-extensions.aaa.ldap
ovirt.engine.extension.binding.jbossmodule.class =
org.ovirt.engineextensions.aaa.ldap.AuthzExtension
ovirt.engine.extension.provides =
org.ovirt.engine.api.extensions.aaa.Authz
config.profile.file.1 = /etc/ovirt-engine/aaa/ad.properties
# Select one
#
include = <openldap.properties>
#include = <389ds.properties>
#include = <rhds.properties>
#include = <ipa.properties>
#include = <iplanet.properties>
#include = <rfc2307-389ds.properties>
#include = <rfc2307-rhds.properties>
#include = <rfc2307-openldap.properties>
#include = <rfc2307-edir.properties>
#include = <rfc2307-generic.properties>
# Server
Red Hat Virtualization 4.2 Administration Guide
236
#
vars.server = ldap1.company.com
# Search user and its password.
#
vars.user = uid=search,cn=users,cn=accounts,dc=company,dc=com
vars.password = 123456
pool.default.serverset.single.server = ${global:vars.server}
pool.default.auth.simple.bindDN = ${global:vars.user}
pool.default.auth.simple.password = ${global:vars.password}
# Create keystore, import certificate chain and uncomment
# if using tls.
pool.default.ssl.startTLS = true
pool.default.ssl.truststore.file = /full/path/to/myrootca.jks
pool.default.ssl.truststore.password = password
上一篇下一篇

猜你喜欢

热点阅读