开源地图服务geoserver源代码研究实践(用户登录与密码验证)

开源地图服务geoserver利用spring security进行用户验证和授权。

一、有关spring security。

       SecurityContextHolder 负责存储安全上下文,保存用户信息,权限等等。
       Authentication 认证信息类,身份信息、密码信息、细节、认证信息。
       UserDetails 用户信息,包含用户的一些基本字段、密码、用户名等。
       UserDetailsService 用户信息,是一个接口、一般可以重数据库中获取用户名、密码创建。
       AuthenticationManager 认证管理类、通过实现该接口实现自定义认证。
       AuthenticationProvider 认证提供者、是一个接口、一个真正的认证、一个是满足某种条件才认证。spring中提供了多种实现         类。

二、关于geoserver地图服务验证。

       首先程序是从GeoServerApplication进入的,我们来看该类的方法init都做了哪些工作。从下面的代码中可以知道方法中创建了GeoServerSecurityManager。

 /** Initialization override which sets up a locator for i18n resources. */
    protected void init() {
        // enable GeoServer custom resource locators
        getResourceSettings().setUseMinifiedResources(false);
        getResourceSettings().setResourceStreamLocator(new GeoServerResourceStreamLocator());

        /*
         * The order string resource loaders are added to IResourceSettings is of importance so we need to add any contributed loader prior to the
         * standard ones so it takes precedence. Otherwise it won't be hit due to GeoServerStringResourceLoader never resolving to null but falling
         * back to the default language
         */
        List<IStringResourceLoader> alternateResourceLoaders =
                getBeansOfType(IStringResourceLoader.class);
        for (IStringResourceLoader loader : alternateResourceLoaders) {
            LOGGER.info("Registering alternate resource loader: " + loader);
            getResourceSettings().getStringResourceLoaders().add(loader);
        }

        getResourceSettings()
                .getStringResourceLoaders()
                .add(0, new GeoServerStringResourceLoader());
        getDebugSettings().setAjaxDebugModeEnabled(false);

        getApplicationSettings().setPageExpiredErrorPage(GeoServerExpiredPage.class);
        // generates infinite redirections, commented out for the moment
        // getSecuritySettings().setCryptFactory(GeoserverWicketEncrypterFactory.get());

        // theoretically, this replaces the old GeoServerRequestEncodingStrategy
        // by making the URLs encrypted at will
        GeoServerSecurityManager securityManager = getBeanOfType(GeoServerSecurityManager.class);
        setRootRequestMapper(
                new DynamicCryptoMapper(getRootRequestMapper(), securityManager, this));

        getRequestCycleListeners().add(new CallbackRequestCycleListener(this));

        WebUIMode webUIMode = getGeoServer().getGlobal().getWebUIMode();
        if (webUIMode == null) {
            webUIMode = WebUIMode.DEFAULT;
        }
        switch (webUIMode) {
            case DO_NOT_REDIRECT:
                getRequestCycleSettings().setRenderStrategy(RenderStrategy.ONE_PASS_RENDER);
                break;
            case REDIRECT:
                getRequestCycleSettings().setRenderStrategy(RenderStrategy.REDIRECT_TO_BUFFER);
                break;
            case DEFAULT:
                getRequestCycleSettings()
                        .setRenderStrategy(
                                defaultIsRedirect
                                        ? RenderStrategy.REDIRECT_TO_BUFFER
                                        : RenderStrategy.ONE_PASS_RENDER);
        }
    }

断点进入到GeoServerSecurityManager内,首先程序从实现spring的接口方法onApplicationEvent进入,GeoServerSecurityManager类定义了reload()方法。该方法大意是存储一个实例后,重新加载的配置将会改变。所以使用reload意为重新加载。

/**
     * Reload the configuration which may have been updated in the meanwhile; after a restore as an
     * instance.
     */
    public void reload() {
        try {
            Resource masterPasswordInfo = security().get(MASTER_PASSWD_INFO_FILENAME);
            if (masterPasswordInfo.getType() != Type.UNDEFINED) {
                LOGGER.warning(
                        masterPasswordInfo.path()
                                + " is a security risk. Please read this file and remove it afterward");
            }
        } catch (Exception e1) {
            throw new RuntimeException(e1);
        }

        // migrate from old security config
        try {
            Version securityVersion = getSecurityVersion();

            boolean migratedFrom21 = false;
            if (securityVersion.compareTo(VERSION_2_2) < 0) {
                migratedFrom21 = migrateFrom21();
            }
            if (securityVersion.compareTo(VERSION_2_3) < 0) {
                removeErroneousAccessDeniedPage();
                migrateFrom22(migratedFrom21);
            }
            if (securityVersion.compareTo(VERSION_2_4) < 0) {
                migrateFrom23();
            }
            if (securityVersion.compareTo(VERSION_2_5) < 0) {
                migrateFrom24();
            }
            if (securityVersion.compareTo(CURR_VERSION) < 0) {
                writeCurrentVersion();
            }
        } catch (Exception e1) {
            throw new RuntimeException(e1);
        }

        // read config and initialize... we do this now since we can be ensured that the spring
        // context has been property initialized, and we can successfully look up security
        // plugins
        KeyStoreProvider keyStoreProvider = getKeyStoreProvider();
        try {
            // check for an outstanding masster password change
            keyStoreProvider.commitMasterPasswordChange();
            // check if there is an outstanding master password change in case of SPrin injection
            init();
            for (GeoServerSecurityProvider securityProvider :
                    GeoServerExtensions.extensions(GeoServerSecurityProvider.class)) {
                securityProvider.init(this);
            }
        } catch (Exception e) {
            throw new BeanCreationException("Error occured reading security configuration", e);
        }
    }

在GeoServerSecurityManager成员变量userGroupServices和roleServices定义了用户组和角色组。用于存储用户信息、角色信息。

    /** cached user groups */
    ConcurrentHashMap<String, GeoServerUserGroupService> userGroupServices =
            new ConcurrentHashMap<String, GeoServerUserGroupService>();

    /** cached role services */
    ConcurrentHashMap<String, GeoServerRoleService> roleServices =
            new ConcurrentHashMap<String, GeoServerRoleService>();

在的reload方法中调用了 migrateFrom21()方法,将创建一个带有方法initializeFromConfig的GeoServerSecurityService接回调。同时如果遇到在userGroupServices没有默认的用户名为admin,密码为geosever的用户,则userGroupServices将为创建该用户。该账户的目的用于用户登录后进行验证。我们来看一下migrateFrom21方法具体源代码。

 boolean migrateFrom21() throws Exception {

        if (role().getType() != Type.UNDEFINED) {
            Resource oldUserFile = security().get("users.properties.old");
            if (oldUserFile.getType() != Type.UNDEFINED) {
                LOGGER.warning(oldUserFile.path() + " could be removed manually");
            }
            return false; // already migrated
        }

        LOGGER.info("Start security migration");

        // master password configuration
        MasterPasswordProviderConfig mpProviderConfig =
                loadMasterPassswordProviderConfig("default");
        if (mpProviderConfig == null) {
            mpProviderConfig = new URLMasterPasswordProviderConfig();
            mpProviderConfig.setName("default");
            mpProviderConfig.setClassName(URLMasterPasswordProvider.class.getCanonicalName());
            mpProviderConfig.setReadOnly(false);

            ((URLMasterPasswordProviderConfig) mpProviderConfig).setURL(new URL("file:passwd"));
            ((URLMasterPasswordProviderConfig) mpProviderConfig).setEncrypting(true);
            saveMasterPasswordProviderConfig(mpProviderConfig, false);

            // save out the default master password
            MasterPasswordProvider mpProvider =
                    loadMasterPasswordProvider(mpProviderConfig.getName());
            Resource propFile = security().get("users.properties");
            Properties userprops = null;
            if (propFile.getType() == Type.RESOURCE) userprops = Util.loadPropertyFile(propFile);
            mpProvider.setMasterPassword(extractMasterPasswordForMigration(userprops));
        }

        MasterPasswordConfig mpConfig = new MasterPasswordConfig();
        mpConfig.setProviderName(mpProviderConfig.getName());
        saveMasterPasswordConfig(mpConfig);

        // check for services.properties, create if necessary
        Resource serviceFile = security().get("services.properties");
        if (serviceFile.getType() == Type.UNDEFINED) {
            org.geoserver.util.IOUtils.copy(
                    Util.class.getResourceAsStream("serviceTemplate.properties"),
                    serviceFile.out());
        }

        long checkInterval = 10000; // 10 secs

        // check for the default user group service, create if necessary
        GeoServerUserGroupService userGroupService =
                loadUserGroupService(XMLUserGroupService.DEFAULT_NAME);

        KeyStoreProvider keyStoreProvider = getKeyStoreProvider();
        keyStoreProvider.reloadKeyStore();
        keyStoreProvider.setUserGroupKey(
                XMLUserGroupService.DEFAULT_NAME, randomPasswdProvider.getRandomPassword(32));
        keyStoreProvider.storeKeyStore();

        PasswordValidator validator = loadPasswordValidator(PasswordValidator.DEFAULT_NAME);
        if (validator == null) {
            // Policy allows any password except null, this is the default
            // at before migration
            PasswordPolicyConfig pwpconfig = new PasswordPolicyConfig();
            pwpconfig.setName(PasswordValidator.DEFAULT_NAME);
            pwpconfig.setClassName(PasswordValidatorImpl.class.getName());
            pwpconfig.setMinLength(0);
            savePasswordPolicy(pwpconfig);
            validator = loadPasswordValidator(PasswordValidator.DEFAULT_NAME);
        }

        validator = loadPasswordValidator(PasswordValidator.MASTERPASSWORD_NAME);
        if (validator == null) {
            // Policy requires a minimum of 8 chars for the master password
            PasswordPolicyConfig pwpconfig = new PasswordPolicyConfig();
            pwpconfig.setName(PasswordValidator.MASTERPASSWORD_NAME);
            pwpconfig.setClassName(PasswordValidatorImpl.class.getName());
            pwpconfig.setMinLength(8);
            savePasswordPolicy(pwpconfig);
            validator = loadPasswordValidator(PasswordValidator.MASTERPASSWORD_NAME);
        }

        if (userGroupService == null) {
            XMLUserGroupServiceConfig ugConfig = new XMLUserGroupServiceConfig();
            ugConfig.setName(XMLUserGroupService.DEFAULT_NAME);
            ugConfig.setClassName(XMLUserGroupService.class.getName());
            ugConfig.setCheckInterval(checkInterval);
            ugConfig.setFileName(XMLConstants.FILE_UR);
            ugConfig.setValidating(true);
            // start with weak encryption, plain passwords can be restored
            ugConfig.setPasswordEncoderName(
                    loadPasswordEncoder(GeoServerPBEPasswordEncoder.class, null, false).getName());
            ugConfig.setPasswordPolicyName(PasswordValidator.DEFAULT_NAME);
            saveUserGroupService(ugConfig);
            userGroupService = loadUserGroupService(XMLUserGroupService.DEFAULT_NAME);
        }

        // check for the default role service, create if necessary
        GeoServerRoleService roleService = loadRoleService(XMLRoleService.DEFAULT_NAME);

        if (roleService == null) {
            XMLRoleServiceConfig gaConfig = new XMLRoleServiceConfig();
            gaConfig.setName(XMLRoleService.DEFAULT_NAME);
            gaConfig.setClassName(XMLRoleService.class.getName());
            gaConfig.setCheckInterval(checkInterval);
            gaConfig.setFileName(XMLConstants.FILE_RR);
            gaConfig.setValidating(true);
            gaConfig.setAdminRoleName(XMLRoleService.DEFAULT_LOCAL_ADMIN_ROLE);
            gaConfig.setGroupAdminRoleName(XMLRoleService.DEFAULT_LOCAL_GROUP_ADMIN_ROLE);
            saveRoleService(gaConfig);
            roleService = loadRoleService(XMLRoleService.DEFAULT_NAME);
        }

        String filterName = GeoServerSecurityFilterChain.BASIC_AUTH_FILTER;
        GeoServerSecurityFilter filter = loadFilter(filterName);
        if (filter == null) {
            BasicAuthenticationFilterConfig bfConfig = new BasicAuthenticationFilterConfig();
            bfConfig.setName(filterName);
            bfConfig.setClassName(GeoServerBasicAuthenticationFilter.class.getName());
            bfConfig.setUseRememberMe(true);
            saveFilter(bfConfig);
        }
        /*filterName = GeoServerSecurityFilterChain.BASIC_AUTH_NO_REMEMBER_ME_FILTER;
        filter = loadFilter(filterName);
        if (filter==null) {
            BasicAuthenticationFilterConfig bfConfig = new BasicAuthenticationFilterConfig();
            bfConfig.setClassName(GeoServerBasicAuthenticationFilter.class.getName());
            bfConfig.setName(filterName);
            bfConfig.setUseRememberMe(false);
            saveFilter(bfConfig);
        }*/
        filterName = GeoServerSecurityFilterChain.FORM_LOGIN_FILTER;
        filter = loadFilter(filterName);
        if (filter == null) {
            UsernamePasswordAuthenticationFilterConfig upConfig =
                    new UsernamePasswordAuthenticationFilterConfig();
            upConfig.setClassName(GeoServerUserNamePasswordAuthenticationFilter.class.getName());
            upConfig.setName(filterName);
            upConfig.setUsernameParameterName(
                    UsernamePasswordAuthenticationFilterConfig.DEFAULT_USERNAME_PARAM);
            upConfig.setPasswordParameterName(
                    UsernamePasswordAuthenticationFilterConfig.DEFAULT_PASSWORD_PARAM);
            saveFilter(upConfig);
        }
        filterName = GeoServerSecurityFilterChain.SECURITY_CONTEXT_ASC_FILTER;
        filter = loadFilter(filterName);
        if (filter == null) {
            SecurityContextPersistenceFilterConfig pConfig =
                    new SecurityContextPersistenceFilterConfig();
            pConfig.setClassName(GeoServerSecurityContextPersistenceFilter.class.getName());
            pConfig.setName(filterName);
            pConfig.setAllowSessionCreation(true);
            saveFilter(pConfig);
        }
        filterName = GeoServerSecurityFilterChain.SECURITY_CONTEXT_NO_ASC_FILTER;
        filter = loadFilter(filterName);
        if (filter == null) {
            SecurityContextPersistenceFilterConfig pConfig =
                    new SecurityContextPersistenceFilterConfig();
            pConfig.setClassName(GeoServerSecurityContextPersistenceFilter.class.getName());
            pConfig.setName(filterName);
            pConfig.setAllowSessionCreation(false);
            saveFilter(pConfig);
        }
        filterName = GeoServerSecurityFilterChain.ANONYMOUS_FILTER;
        filter = loadFilter(filterName);
        if (filter == null) {
            AnonymousAuthenticationFilterConfig aConfig = new AnonymousAuthenticationFilterConfig();
            aConfig.setClassName(GeoServerAnonymousAuthenticationFilter.class.getName());
            aConfig.setName(filterName);
            saveFilter(aConfig);
        }
        filterName = GeoServerSecurityFilterChain.REMEMBER_ME_FILTER;
        filter = loadFilter(filterName);
        if (filter == null) {
            RememberMeAuthenticationFilterConfig rConfig =
                    new RememberMeAuthenticationFilterConfig();
            rConfig.setClassName(GeoServerRememberMeAuthenticationFilter.class.getName());
            rConfig.setName(filterName);
            saveFilter(rConfig);
        }
        filterName = GeoServerSecurityFilterChain.FILTER_SECURITY_INTERCEPTOR;
        filter = loadFilter(filterName);
        if (filter == null) {
            SecurityInterceptorFilterConfig siConfig = new SecurityInterceptorFilterConfig();
            siConfig.setClassName(GeoServerSecurityInterceptorFilter.class.getName());
            siConfig.setName(filterName);
            siConfig.setAllowIfAllAbstainDecisions(false);
            siConfig.setSecurityMetadataSource("geoserverMetadataSource");
            saveFilter(siConfig);
        }
        filterName = GeoServerSecurityFilterChain.FILTER_SECURITY_REST_INTERCEPTOR;
        filter = loadFilter(filterName);
        if (filter == null) {
            SecurityInterceptorFilterConfig siConfig = new SecurityInterceptorFilterConfig();
            siConfig.setClassName(GeoServerSecurityInterceptorFilter.class.getName());
            siConfig.setName(filterName);
            siConfig.setAllowIfAllAbstainDecisions(false);
            siConfig.setSecurityMetadataSource("restFilterDefinitionMap");
            saveFilter(siConfig);
        }
        filterName = GeoServerSecurityFilterChain.FORM_LOGOUT_FILTER;
        filter = loadFilter(filterName);
        if (filter == null) {
            LogoutFilterConfig loConfig = new LogoutFilterConfig();
            loConfig.setClassName(GeoServerLogoutFilter.class.getName());
            loConfig.setName(filterName);
            saveFilter(loConfig);
        }
        filterName = GeoServerSecurityFilterChain.DYNAMIC_EXCEPTION_TRANSLATION_FILTER;
        filter = loadFilter(filterName);
        if (filter == null) {
            ExceptionTranslationFilterConfig bfConfig = new ExceptionTranslationFilterConfig();
            bfConfig.setClassName(GeoServerExceptionTranslationFilter.class.getName());
            bfConfig.setName(filterName);
            bfConfig.setAuthenticationFilterName(null);
            bfConfig.setAccessDeniedErrorPage("/accessDenied.jsp");
            saveFilter(bfConfig);
        }
        filterName = GeoServerSecurityFilterChain.GUI_EXCEPTION_TRANSLATION_FILTER;
        filter = loadFilter(filterName);
        if (filter == null) {
            ExceptionTranslationFilterConfig bfConfig = new ExceptionTranslationFilterConfig();
            bfConfig.setClassName(GeoServerExceptionTranslationFilter.class.getName());
            bfConfig.setName(filterName);
            bfConfig.setAuthenticationFilterName(GeoServerSecurityFilterChain.FORM_LOGIN_FILTER);
            bfConfig.setAccessDeniedErrorPage("/accessDenied.jsp");
            saveFilter(bfConfig);
        }

        // check for the default auth provider, create if necessary
        GeoServerAuthenticationProvider authProvider =
                loadAuthenticationProvider(GeoServerAuthenticationProvider.DEFAULT_NAME);
        if (authProvider == null) {
            UsernamePasswordAuthenticationProviderConfig upAuthConfig =
                    new UsernamePasswordAuthenticationProviderConfig();
            upAuthConfig.setName(GeoServerAuthenticationProvider.DEFAULT_NAME);
            upAuthConfig.setClassName(UsernamePasswordAuthenticationProvider.class.getName());
            upAuthConfig.setUserGroupServiceName(userGroupService.getName());

            saveAuthenticationProvider(upAuthConfig);
            authProvider = loadAuthenticationProvider(GeoServerAuthenticationProvider.DEFAULT_NAME);
        }

        // save the top level config
        SecurityManagerConfig config = new SecurityManagerConfig();
        config.setRoleServiceName(roleService.getName());
        config.getAuthProviderNames().add(authProvider.getName());
        config.setEncryptingUrlParams(false);

        // start with weak encryption
        config.setConfigPasswordEncrypterName(
                loadPasswordEncoder(GeoServerPBEPasswordEncoder.class, true, false).getName());

        // setup the default remember me service
        RememberMeServicesConfig rememberMeConfig = new RememberMeServicesConfig();
        rememberMeConfig.setClassName(GeoServerTokenBasedRememberMeServices.class.getName());
        config.setRememberMeService(rememberMeConfig);

        config.setFilterChain(GeoServerSecurityFilterChain.createInitialChain());
        saveSecurityConfig(config);

        // TODO: just call initializeFrom
        userGroupService.setSecurityManager(this);
        roleService.setSecurityManager(this);

        // populate the user group and role service
        GeoServerUserGroupStore userGroupStore = userGroupService.createStore();
        GeoServerRoleStore roleStore = roleService.createStore();

        // migrate from users.properties
        Resource usersFile = security().get("users.properties");
        if (usersFile.getType() == Type.RESOURCE) {
            // load user.properties populate the services
            Properties props = Util.loadPropertyFile(usersFile);

            UserAttributeEditor configAttribEd = new UserAttributeEditor();

            for (Iterator<Object> iter = props.keySet().iterator(); iter.hasNext(); ) {
                // the attribute editors parses the list of strings into password, username and
                // enabled
                // flag
                String username = (String) iter.next();
                configAttribEd.setAsText(props.getProperty(username));

                // if the parsing succeeded turn that into a user object
                UserAttribute attr = (UserAttribute) configAttribEd.getValue();
                if (attr != null) {
                    GeoServerUser user =
                            userGroupStore.createUserObject(
                                    username, attr.getPassword(), attr.isEnabled());
                    userGroupStore.addUser(user);

                    for (GrantedAuthority auth : attr.getAuthorities()) {
                        String roleName =
                                GeoServerRole.ADMIN_ROLE.getAuthority().equals(auth.getAuthority())
                                        ? XMLRoleService.DEFAULT_LOCAL_ADMIN_ROLE
                                        : auth.getAuthority();
                        GeoServerRole role = roleStore.getRoleByName(roleName);
                        if (role == null) {
                            role = roleStore.createRoleObject(roleName);
                            roleStore.addRole(role);
                        }
                        roleStore.associateRoleToUser(role, username);
                    }
                }
            }
        } else {
            // no user.properties, populate with default user and roles
            if (userGroupService.getUserByUsername(GeoServerUser.ADMIN_USERNAME) == null) {
                userGroupStore.addUser(GeoServerUser.createDefaultAdmin());
                GeoServerRole localAdminRole =
                        roleStore.createRoleObject(XMLRoleService.DEFAULT_LOCAL_ADMIN_ROLE);
                roleStore.addRole(localAdminRole);
                roleStore.associateRoleToUser(localAdminRole, GeoServerUser.ADMIN_USERNAME);
            }
        }

        // add the local group administrator role
        if (roleStore.getRoleByName(XMLRoleService.DEFAULT_LOCAL_GROUP_ADMIN_ROLE) == null) {
            roleStore.addRole(
                    roleStore.createRoleObject(XMLRoleService.DEFAULT_LOCAL_GROUP_ADMIN_ROLE));
        }

        // replace all occurrences of ROLE_ADMINISTRATOR  in the property files
        // TODO Justin, a little bit brute force, is this ok ?
        for (String filename :
                new String[] {"services.properties", "layers.properties", "rest.properties"}) {
            Resource file = security().get(filename);
            if (file.getType() == Type.UNDEFINED) {
                continue;
            }
            List<String> lines = new ArrayList<String>();
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(file.in()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    lines.add(
                            line.replace(
                                    GeoServerRole.ADMIN_ROLE.getAuthority(),
                                    XMLRoleService.DEFAULT_LOCAL_ADMIN_ROLE));
                }
            }
            try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.out()))) {
                for (String s : lines) {
                    writer.println(s);
                }
            }
        }

        // check for roles in services.properties but not in user.properties
        serviceFile = security().get("services.properties");
        if (serviceFile.getType() != Type.UNDEFINED) {
            Properties props = Util.loadPropertyFile(serviceFile);
            for (Entry<Object, Object> entry : props.entrySet()) {
                StringTokenizer tokenizer = new StringTokenizer((String) entry.getValue(), ",");
                while (tokenizer.hasMoreTokens()) {
                    String roleName = tokenizer.nextToken().trim();
                    if (roleName.length() > 0) {
                        if (roleStore.getRoleByName(roleName) == null) {
                            roleStore.addRole(roleStore.createRoleObject(roleName));
                        }
                    }
                }
            }
        }

        // check for  roles in data.properties but not in user.properties
        Resource dataFile = security().get("layers.properties");
        if (dataFile.getType() == Type.RESOURCE) {
            Properties props = Util.loadPropertyFile(dataFile);
            for (Entry<Object, Object> entry : props.entrySet()) {
                if ("mode".equals(entry.getKey().toString())) continue; // skip mode directive
                StringTokenizer tokenizer = new StringTokenizer((String) entry.getValue(), ",");
                while (tokenizer.hasMoreTokens()) {
                    String roleName = tokenizer.nextToken().trim();
                    if (roleName.length() > 0 && roleName.equals("*") == false) {
                        if (roleStore.getRoleByName(roleName) == null)
                            roleStore.addRole(roleStore.createRoleObject(roleName));
                    }
                }
            }
        }

        // persist the changes
        roleStore.store();
        userGroupStore.store();

        // first part of migration finished, rename old file
        if (usersFile.getType() != Type.UNDEFINED) {
            Resource oldUserFile = dataDir.get(usersFile.path() + ".old");
            usersFile.renameTo(oldUserFile);
            LOGGER.info("Renamed " + usersFile.path() + " to " + oldUserFile.path());
        }

        LOGGER.info("End security migration");
        return true;
    }

    /** migration from 2.2.x to 2.3.x return <code>true</code> if migration has taken place */
    boolean migrateFrom22(boolean migratedFrom21) throws Exception {

        String filterName = GeoServerSecurityFilterChain.ROLE_FILTER;
        GeoServerSecurityFilter filter = loadFilter(filterName);

        Resource logoutFilterDir =
                filterRoot().get(GeoServerSecurityFilterChain.FORM_LOGOUT_FILTER);
        Resource oldLogoutFilterConfig = logoutFilterDir.get("config.xml.2.2.x");
        Resource oldSecManagerConfig = security().get("config.xml.2.2.x");

        if (filter != null) {
            if (oldLogoutFilterConfig.getType() == Type.RESOURCE)
                LOGGER.warning(oldLogoutFilterConfig.path() + " could be removed manually");
            if (oldSecManagerConfig.getType() == Type.RESOURCE)
                LOGGER.warning(oldSecManagerConfig.path() + " could be removed manually");
            return false; // already migrated
        }

        // add role filter
        RoleFilterConfig rfConfig = new RoleFilterConfig();
        rfConfig.setClassName(GeoServerRoleFilter.class.getName());
        rfConfig.setName(filterName);
        rfConfig.setHttpResponseHeaderAttrForIncludedRoles(
                GeoServerRoleFilter.DEFAULT_HEADER_ATTRIBUTE);
        rfConfig.setRoleConverterName(GeoServerRoleFilter.DEFAULT_ROLE_CONVERTER);
        saveFilter(rfConfig);

        // add ssl filter
        SSLFilterConfig sslConfig = new SSLFilterConfig();
        sslConfig.setClassName(GeoServerSSLFilter.class.getName());
        sslConfig.setName(GeoServerSecurityFilterChain.SSL_FILTER);
        sslConfig.setSslPort(443);
        saveFilter(sslConfig);

        // set redirect url after successful logout
        if (!migratedFrom21)
            org.geoserver.util.IOUtils.copy(
                    logoutFilterDir.get("config.xml").in(), oldLogoutFilterConfig.out());
        LogoutFilterConfig loConfig =
                (LogoutFilterConfig)
                        loadFilterConfig(GeoServerSecurityFilterChain.FORM_LOGOUT_FILTER);
        loConfig.setRedirectURL(GeoServerLogoutFilter.URL_AFTER_LOGOUT);
        saveFilter(loConfig);

        if (!migratedFrom21)
            org.geoserver.util.IOUtils.copy(
                    security().get("config.xml").in(), oldSecManagerConfig.out());
        SecurityManagerConfig config = loadSecurityConfig();
        for (RequestFilterChain chain : config.getFilterChain().getRequestChains()) {
            if (chain.getFilterNames()
                    .contains(GeoServerSecurityFilterChain.SECURITY_CONTEXT_ASC_FILTER)) {
                chain.setAllowSessionCreation(true);
                chain.getFilterNames()
                        .remove(GeoServerSecurityFilterChain.SECURITY_CONTEXT_ASC_FILTER);
            }
            if (chain.getFilterNames()
                    .contains(GeoServerSecurityFilterChain.SECURITY_CONTEXT_NO_ASC_FILTER)) {
                chain.setAllowSessionCreation(false);
                chain.getFilterNames()
                        .remove(GeoServerSecurityFilterChain.SECURITY_CONTEXT_NO_ASC_FILTER);
            }
            // prepare web chain
            if (GeoServerSecurityFilterChain.WEB_CHAIN_NAME.equals(chain.getName())) {
                // replace exception translation filter
                int index =
                        chain.getFilterNames()
                                .indexOf(
                                        GeoServerSecurityFilterChain
                                                .GUI_EXCEPTION_TRANSLATION_FILTER);
                if (index != -1)
                    chain.getFilterNames()
                            .set(
                                    index,
                                    GeoServerSecurityFilterChain
                                            .DYNAMIC_EXCEPTION_TRANSLATION_FILTER);
                // inject form login filter if necessary
                if (chain.getFilterNames().indexOf(GeoServerSecurityFilterChain.FORM_LOGIN_FILTER)
                        == -1) {
                    index =
                            chain.getFilterNames()
                                    .indexOf(GeoServerSecurityFilterChain.ANONYMOUS_FILTER);
                    if (index == -1)
                        index =
                                chain.getFilterNames()
                                        .indexOf(
                                                GeoServerSecurityFilterChain
                                                        .FILTER_SECURITY_INTERCEPTOR);
                    if (index != -1)
                        chain.getFilterNames()
                                .add(index, GeoServerSecurityFilterChain.FORM_LOGIN_FILTER);
                }
            }

            // remove dynamic translation filter
            chain.getFilterNames()
                    .remove(GeoServerSecurityFilterChain.DYNAMIC_EXCEPTION_TRANSLATION_FILTER);
            chain.getFilterNames().remove(GeoServerSecurityFilterChain.FILTER_SECURITY_INTERCEPTOR);
            chain.getFilterNames()
                    .remove(GeoServerSecurityFilterChain.FILTER_SECURITY_REST_INTERCEPTOR);
        }
        // gui filter not needed any more
        removeFilter(
                loadFilterConfig(GeoServerSecurityFilterChain.GUI_EXCEPTION_TRANSLATION_FILTER));
        saveSecurityConfig(config);

        // load and store all filter configuration
        // some filter configurations may have their class name as top level xml element in
        // config.xml,
        // the alias should be used instead, this was bug fixed during GSIP 82
        if (!migratedFrom21) {
            for (String fName : listFilters()) {
                SecurityFilterConfig fConfig = loadFilterConfig(fName);
                if (fConfig != null) saveFilter(fConfig);
            }
        }

        return true;
    }

初始为用户名和密码后,我们来看一下验证。geoserver使用spring的拦截器实现用户名密码登录。自定义拦截器bean配置在web目录下的core、src、main、java目录下的applicationContext中。我们来看一下配置文件。

	<!-- login button -->
	<bean id="geoserverFormLoginButton" class="org.geoserver.web.LoginFormInfo">
		<property name="id" value="geoserverFormLoginButton" />
		<property name="titleKey" value="login" />
		<property name="descriptionKey" value="GeoServerBasePage.description" />
		<property name="componentClass" value="org.geoserver.web.GeoServerBasePage" />
		<property name="name" value="form" />
		<property name="icon" value="img/icons/silk/door-in.png" />
		<property name="filterClass" value="org.geoserver.security.filter.GeoServerUserNamePasswordAuthenticationFilter" />
		<property name="include" value="include_login_form.html" />
		<property name="loginPath" value="j_spring_security_check" />
	</bean>

我们来看一下GeoServerUserNamePasswordAuthenticationFilter拦截器的定义。

public class GeoServerUserNamePasswordAuthenticationFilter extends GeoServerCompositeFilter
        implements GeoServerAuthenticationFilter {

    // public static final String URL_FOR_LOGIN = "/j_spring_security_check";
    public static final String URL_LOGIN_SUCCCESS = "/web";
    public static final String URL_LOGIN_FAILURE =
            "/web/wicket/bookmarkable/org.geoserver.web.GeoServerLoginPage?error=true";
    public static final String URL_LOGIN_FORM =
            "/web/wicket/bookmarkable/org.geoserver.web.GeoServerLoginPage?error=false";
    // public static final String URL_LOGIN_FORM="/admin/login.do";

    private LoginUrlAuthenticationEntryPoint aep;
    String[] pathInfos;
    //https://www.cnblogs.com/lexiaofei/p/7018405.html?utm_source=itdadao&utm_medium=referral

    @Override
    public void initializeFromConfig(SecurityNamedServiceConfig config) throws IOException {
        super.initializeFromConfig(config);

        pathInfos = GeoServerSecurityFilterChain.FORM_LOGIN_CHAIN.split(",");

        UsernamePasswordAuthenticationFilterConfig upConfig =
                (UsernamePasswordAuthenticationFilterConfig) config;

        aep = new LoginUrlAuthenticationEntryPoint(URL_LOGIN_FORM);
        aep.setForceHttps(false);
        try {
            aep.afterPropertiesSet();
        } catch (Exception e2) {
            throw new IOException(e2);
        }

        RememberMeServices rms = securityManager.getRememberMeService();

        // add login filter
        UsernamePasswordAuthenticationFilter filter =
                new UsernamePasswordAuthenticationFilter() {
                    @Override
                    protected boolean requiresAuthentication(
                            HttpServletRequest request, HttpServletResponse response) {

                        for (String pathInfo : pathInfos) {
                            if (getRequestPath(request).startsWith(pathInfo)) return true;
                        }
                        return false;
                    }
                };




        filter.setPasswordParameter(upConfig.getPasswordParameterName());
        filter.setUsernameParameter(upConfig.getUsernameParameterName());
        filter.setAuthenticationManager(getSecurityManager().authenticationManager());

        filter.setRememberMeServices(rms);
        GeoServerWebAuthenticationDetailsSource s = new GeoServerWebAuthenticationDetailsSource();
        filter.setAuthenticationDetailsSource(s);

        filter.setAllowSessionCreation(false);
        // filter.setFilterProcessesUrl(URL_FOR_LOGIN);

        SimpleUrlAuthenticationSuccessHandler successHandler =
                new SimpleUrlAuthenticationSuccessHandler();
        successHandler.setDefaultTargetUrl(URL_LOGIN_SUCCCESS);
        filter.setAuthenticationSuccessHandler(successHandler);

        SimpleUrlAuthenticationFailureHandler failureHandler =
                new SimpleUrlAuthenticationFailureHandler();
        // TODO, check this when using encrypting of URL parameters
        failureHandler.setDefaultFailureUrl(URL_LOGIN_FAILURE);
        filter.setAuthenticationFailureHandler(failureHandler);

        // filter.afterPropertiesSet();
        getNestedFilters().add(filter);
    }

    @Override
    public AuthenticationEntryPoint getAuthenticationEntryPoint() {
        return aep;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        req.setAttribute(GeoServerSecurityFilter.AUTHENTICATION_ENTRY_POINT_HEADER, aep);
        super.doFilter(req, res, chain);
    }

    /** @see org.geoserver.security.filter.GeoServerAuthenticationFilter#applicableForHtml() */
    @Override
    public boolean applicableForHtml() {
        return true;
    }

    /** @see org.geoserver.security.filter.GeoServerAuthenticationFilter#applicableForServices() */
    @Override
    public boolean applicableForServices() {
        return false;
    }
}
GeoServerUserNamePasswordAuthenticationFilter类实现了initializeFromConfig方法。配置了UsernamePasswordAuthenticationFilter相关参数,如setPasswordParameter设置密码参数、设置setUsernameParameter用户参数、设置认证管理类setAuthenticationManager、设置成功跳转setAuthenticationSuccessHandler等。

在上面的migrateFrom21方法中,最后还设置配置config,设置了用户名密码验证提供类。在用户名密码提供类UsernamePasswordAuthenticationProvider的实现接口中有配置config参数,利用该参数获取admin用户名的验证实例UserDetailsService。该UserDetailsService是我们在migrateFrom21方法中创建好的,UsernamePasswordAuthenticationProvider的成员变量DaoAuthenticationProvider利用setUserDetailsService方法设置该正确验证实例。

好了,做好了前期的创建正确UserDetailsService和获取前台接收的用户名和密码后,利用Spring Security中的相关类对用户进行验证。


                                                                      更多内容,请关注公众号

                                                                

转载自:https://blog.csdn.net/u010608964/article/details/84344748

You may also like...