Eliminating vurnabilities in the Spring SpEL - spring

I'm testing the Spring SpEL and I thinking if it is possible to somehow limit what kind of SpEL query can be provided, to avoid some unwanted code injection? I just want to get values from some object, so is it possible to block other types of operations? I can't find such functionality in the Spring documentation.
For instance, I just want to allow to check if the value from the test object equals XYZ.
Test test = new Test("XYZ", 999);
ExpressionParser expressionParser = new SpelExpressionParser();
Expression expression = expressionParser.parseExpression("value eq 'XYZ'");
System.out.println(expression.getValue(new StandardEvaluationContext(test)));
However, I would like to limit which expressions are valid. I don't what to evaluate expressions which allow to execute some code, for instance:
Expression expression = expressionParser.parseExpression("''.getClass().forName('java.lang.Runtime').getMethods()[6]");

As #ArtemBilan mentioned in the comment, the solution to limit the SpEL language syntax and eliminate unwanted code execution is to use the SimpleEvaluationContext class, for instance:
SimpleEvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding()
.withInstanceMethods()
.withRootObject(test)
.build();

Related

Kotlin: Keeping multiple profiles inside #ActiveProfiles annotation?

I know that in java, multiple active profiles can be kept using -
#ActiveProfiles({"profile1", "profile2"})
But I need a similar construct for kotlin. Above doesnt work with kotlin and gives error saying - Unexpected tokens (use ';' to separate expressions on the same line). I also tried #ActiveProfiles(profile = arrayOf("profile1", "profile2")) and also tried #Profile("profile1 & profile2"). Nothing seems to work. Please help.
If you check the source of #ActiveProfiles you'll see the following constructor:
/**
* Alias for {#link #profiles}.
* <p>This attribute may <strong>not</strong> be used in conjunction with
* {#link #profiles}, but it may be used <em>instead</em> of {#link #profiles}.
*/
#AliasFor("profiles")
String[] value() default {};
This means its expecting an array of strings for 'profiles' -> just create an array as you normally do it in Kotlin and pass it to the constructor like that:
#ActiveProfiles(profiles = arrayOf("profile1", "profile1"))
The shortest form would be:
#ActiveProfiles(profiles = ["profile1", "profile2"])

Is including parameter in params redundant, when also using #RequestPram?

In a example like:
#GetMapping(value = "/artists", params = "genre")
public List<Artist> getArtists(#RequestParam String genre) {
}
is including genre in the params redundant since it is also declared using #RequestParam in the method signature ?
When trying to map to different methods for the same URL, is the method signature the one that metters, or is also defining params necessary?
In the #RequestMapping annotation (and other HTTP method specific variants), the params element is meant for narrowing the request mappings based on query parameter conditions. From the documentation:
The parameters of the mapped request, narrowing the primary mapping.
Same format for any environment: a sequence of myParam=myValue style expressions, with a request only mapped if each such parameter is found to have the given value. Expressions can be negated by using the != operator, as in myParam!=myValue. myParam style expressions are also supported, with such parameters having to be present in the request (allowed to have any value). Finally, !myParam style expressions indicate that the specified parameter is not supposed to be present in the request.
In the other hand, the #RequestParam annotation allows you to bind a query parameter to a method argument.
Refer to the documentation for details.

Spring Spel for roles

I have a custom requirement where I want to decide if an API can be accessed depending on certain roles. I am using Spring framework.
I want to support something like this:
1. (R1 || R2) && (R3 || R4)
2. (R1) || (R2 && R3)
where R represents a role. || and && are logical operators denoting or and and respectively.
This expression should be evaluated against an input array of roles.
So if the input array is [R2, R4], then the first expression evaluates to true and second expression evaluates to false.
I found something similar using SPEL but instead of R which can be any String like customer, employee, etc, they are using boolean expressions value like true or 6 == 6, etc
You can use method security based on roles with SpEL.
#PreAuthorize("hasRole('ROLE_A') or hasRole('ROLE_B')")
public void yourMethod() {
// ...
}
I solved the above problem using the following:
I used SpEL as provided by Spring.
SpEL supports property replacement.
Code for replacement:
Inventor tesla = new Inventor("Nikola Tesla");
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("name == Nikola Tesla");
String name = (String) exp.getValue(tesla);
Here, the name property will be replaced by Nikola Tesla.
This should be used when the name property has different value each time the expression is evaluated.
If the value of name property is the same every time, consider using EvaluationContext.
Now talking about the boolean expressions, you will have to compulsorily substitute values for properties, because in above example, property name can take null as the default value, but a string role can't take true or false without substitution.
And let's suppose that the SpEL contains some roles which I am not aware of, I won't be able to replace them with true and false. To solve this, I used something similar to #PreAuthorize which has the method hasRole().
Code for reference:
String roles = "(hasRole('admin') or hasRole('superAdmin')) and hasRole('modifier')"
Expression roleExpression = parser.parseExpression(roles);
StandardEvaluationContext roleContext = new StandardEvaluationContext(new SpelHelper());
roleContext.addPropertyAccessor(new MapAccessor()); // this line might be useless
Boolean hasCorrectRole = roleExpression.getValue(roleContext, Boolean.class);
class SpelHelper {
public boolean hasRole(String role) {
// some logic like current user roles have the role passed as argument
return true;
}
}
Full documentation at:
https://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/expressions.html
Also, refer Boolean Expression Evaluation in Java
This answer suggests using JEXL and the answer will give you a fair idea what to do to replace properties.

Why cant nullable arrays/hashmaps be accessed using []

When I have a nullable array/list/hashmap such as
var x: ArrayList<String>? = null
I know can access the element at index 1 like so
var element = x?.get(1)
or I could do it in a unsafe way like this
var element = x!![1]
but why can't I do something like this
var element = x?[1]
what's the difference between getting elements from an array using the first example and the last example, and why is the last example not allowed?
In the first example, you're using the safe call operator ?. to call the get function with it.
In the second example, you're using the [] operator on the non-nullable return value of the x!! expression, which of course is allowed.
However, the language simply doesn't have a ?[] operator, which would be the combination of the two. The other operators offered are also don't have null-safe variants: there's no ?+ or ?&& or anything like that. This is just a design decision by the language creators. (The full list of available operators is here).
If you want to use operators, you need to call them on non-nullable expressions - only functions get the convenience of the safe call operator.
You could also define your own operator as an extension of the nullable type:
operator fun <T> List<T>?.get(index: Int) = this?.get(index)
val x: ArrayList<String>? = null
val second = x[2] // null
This would get you a neater syntax, but it hides the underlying null handling, and might confuse people who don't expect this custom extension on collections.

Mocking RestTemplate call with Mockito

I have the following code that is inside of a method that I am testing. I need to mock this restTemplate call to get predictable result.
GitHubEmail[] gitHubEmails = restTemplate
.getForObject(userEmailsUrl, GitHubEmail[].class, oAuthToken);
In the test method, I do this:
RestTemplate mockRestTemplate = Mockito.mock(RestTemplate.class);
GitHubEmail fakeGitHubEmail = new GitHubEmail("testemail#email.com",
false, false, GitHubEmailVisibility.PRIVATE);
GitHubEmail[] fakeEmails = {fakeGitHubEmail};
Mockito.when(mockRestTemplate.getForObject(
Mockito.eq(userUrl),
Mockito.eq(GitHubEmail[].class),
Mockito.eq(testOAuthToken)))
.thenReturn(fakeEmails);
gitHubService.setRestTemplate(mockRestTemplate);
User user = gitHubService.getUser(testOAuthToken);
Things aren't working as I expect them to... When I examine gitHubEmails variable in my method I am testing, it's null.
Why isn't this working?
The current code as it is right now does not contain any mistakes. However, there are two things we don't see from the given code:
We don't see that testOAuthToken is properly passed to the oAuthToken variable within the githubService.
We don't see that the userUrl is passed to the userEmailsUrl within githubService.
You should make sure that all properties match the one you expect them to be, otherwise the mocking doesn't work. Given that you named one property userUrl and the other one userEmailsUrl, it's likely that the error is there.
Usually, when I encounter these error-prone mocking situations, I use "any matchers" (any(), anyString(), ...) when mocking and then after the call and the assertions, I use Mockito.verify() to check if the parameters match:
Mockito.when(mockRestTemplate.getForObject(
Mockito.anyString(), // Use anyString()
Mockito.eq(GitHubEmail[].class),
Mockito.anyString())) // Use anyString()
.thenReturn(fakeEmails);
// Call + Assertions ...
Mockito.verify(mockRestTemplate).getForObject(
Mockito.eq(userUrl), // Use eq()
Mockito.eq(GitHubEmail[].class),
Mockito.eq(testOAuthToken)); // Use eq()
The reason for this is that the verify() output gives a lot more feedback. Rather than just failing, it will tell why it failed when:
The mocked method was called with different arguments, and which arguments
The mocked object had different methods being invoked

Resources