Some Security Expressions cause NPE when used within Query annotation

Added trustResolver, roleHierarchy, permissionEvaluator, defaultRolePrefix
fields to SecurityEvaluationContextExtension.

Closes gh-11196
Closes gh-11290
This commit is contained in:
Evgeniy Cheban 2022-05-17 19:55:45 +03:00 committed by Steve Riesenberg
parent 649428b49a
commit cf559ab224
No known key found for this signature in database
GPG Key ID: 5F311AB48A55D521
2 changed files with 37 additions and 3 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,7 +17,13 @@
package org.springframework.security.data.repository.query; package org.springframework.security.data.repository.query;
import org.springframework.data.spel.spi.EvaluationContextExtension; import org.springframework.data.spel.spi.EvaluationContextExtension;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.DenyAllPermissionEvaluator;
import org.springframework.security.access.expression.SecurityExpressionRoot; import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
@ -77,12 +83,21 @@ import org.springframework.security.core.context.SecurityContextHolder;
* it. * it.
* *
* @author Rob Winch * @author Rob Winch
* @author Evgeniy Cheban
* @since 4.0 * @since 4.0
*/ */
public class SecurityEvaluationContextExtension implements EvaluationContextExtension { public class SecurityEvaluationContextExtension implements EvaluationContextExtension {
private Authentication authentication; private Authentication authentication;
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
private PermissionEvaluator permissionEvaluator = new DenyAllPermissionEvaluator();
private String defaultRolePrefix = "ROLE_";
/** /**
* Creates a new instance that uses the current {@link Authentication} found on the * Creates a new instance that uses the current {@link Authentication} found on the
* {@link org.springframework.security.core.context.SecurityContextHolder}. * {@link org.springframework.security.core.context.SecurityContextHolder}.
@ -106,8 +121,13 @@ public class SecurityEvaluationContextExtension implements EvaluationContextExte
@Override @Override
public SecurityExpressionRoot getRootObject() { public SecurityExpressionRoot getRootObject() {
Authentication authentication = getAuthentication(); Authentication authentication = getAuthentication();
return new SecurityExpressionRoot(authentication) { SecurityExpressionRoot root = new SecurityExpressionRoot(authentication) {
}; };
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(this.roleHierarchy);
root.setPermissionEvaluator(this.permissionEvaluator);
root.setDefaultRolePrefix(this.defaultRolePrefix);
return root;
} }
private Authentication getAuthentication() { private Authentication getAuthentication() {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,7 +20,10 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.security.access.expression.DenyAllPermissionEvaluator;
import org.springframework.security.access.expression.SecurityExpressionRoot; import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
@ -69,6 +72,17 @@ public class SecurityEvaluationContextExtensionTests {
assertThat(getRoot().getAuthentication()).isSameAs(explicit); assertThat(getRoot().getAuthentication()).isSameAs(explicit);
} }
@Test
public void getRootObjectWhenAdditionalFieldsNotSetThenVerifyDefaults() {
TestingAuthenticationToken explicit = new TestingAuthenticationToken("explicit", "password", "ROLE_EXPLICIT");
this.securityExtension = new SecurityEvaluationContextExtension(explicit);
SecurityExpressionRoot root = getRoot();
assertThat(root).extracting("trustResolver").isInstanceOf(AuthenticationTrustResolverImpl.class);
assertThat(root).extracting("roleHierarchy").isInstanceOf(NullRoleHierarchy.class);
assertThat(root).extracting("permissionEvaluator").isInstanceOf(DenyAllPermissionEvaluator.class);
assertThat(root).extracting("defaultRolePrefix").isEqualTo("ROLE_");
}
private SecurityExpressionRoot getRoot() { private SecurityExpressionRoot getRoot() {
return this.securityExtension.getRootObject(); return this.securityExtension.getRootObject();
} }