Должен ли Spring Security ACL использоваться с WebSecurityExpressionHandler?

#spring #spring-security #spring-security-acl

Вопрос:

Я следовал этому руководству, чтобы настроить безопасность с помощью списков управления доступом, которые отлично работают. После этого я также попытался реализовать ACL в WebSecurityConfigurerAdapter. Итак, я настроил компонент, который создаст DefaultWebSecurityExpressionHandler:

     @Bean
    public DefaultWebSecurityExpressionHandler webExpressionHandler(AclPermissionEvaluator aclPermissionEvaluator) {
        final DefaultWebSecurityExpressionHandler webSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
        AclPermissionEvaluator permissionEvaluator = aclPermissionEvaluator();
        webSecurityExpressionHandler.setPermissionEvaluator(permissionEvaluator);
        return webSecurityExpressionHandler;
    }
 

И я бы применил его к HttpSecurity в моем WebSecurityConfigurerAdapter:

 @Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .authorizeRequests()
        .expressionHandler(webExpressionHandlerWithACL)
        .antMatchers(HttpMethod.PUT, "/api/user/users/{ID}").access("isAuthenticated() and hasPermission(#ID, 'xxx.xxx.xxx.xxx.xxx.UserDto', 'write')")
        .anyRequest().authenticated()
        .and()
        .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
        .and()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);
}
 

Но это просто не работает. Это точно такое же выражение работает в теге @PreAuthorize, но здесь его просто нет.
Я отладил его и обнаружил, что точная точка сбоя находится в классе JdbcAclServiceImpl, предоставляемом Spring в следующем методе:

 @Override
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids)
        throws NotFoundException {
    Map<ObjectIdentity, Acl> result = this.lookupStrategy.readAclsById(objects, sids);
    // Check every requested object identity was found (throw NotFoundException if
    // needed)
    for (ObjectIdentity oid : objects) {
        if (!result.containsKey(oid)) {
            throw new NotFoundException("Unable to find ACL information for object identity '"   oid   "'");
        }
    }
    return resu<
}
 

Несмотря на то, что предоставленные параметры такие же, как если бы я использовал тег @PreAuthorize , result.containsKey(oid) just НЕ МОЖЕТ найти acl в, хотя я вижу его с помощью отладчика, и я вижу, что oid он должен соответствовать ему.

Итак, мой вопрос: должен ли Spring Security ACL вообще работать для защиты маршрутов или он должен использоваться только для защиты методов?

кстати, я использую Spring boot 2.5.5

Ответ №1:

Я нашел проблему. У класса AclPermissionEvaluator есть метод public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) , который вызывается. Если я использую его как webExpressionHandler, то Serializable targetId это всегда строка. Но для того, чтобы это сработало, оно должно быть длинным. Итак, одним из решений является расширение AclPermissionEvaluator и переопределение рассматриваемого метода, чтобы он преобразовывал строку в Long, а затем она работала. Не забудьте затем фактически использовать пользовательский AclPermissionEvaluator .