Skip to content

@Secured annotation unintuitive when using expressions #2012

Description

@bastian-schlueter

Expected Behavior

@Secured({
    SecurityRule.IS_ANONYMOUS,
    "#{ true }"
})

I would expect the annotated endpoint to permit any request, since the first value is a token to allow unauthorized access and even the second value, an expression, evaluates to true.

I would also expect this configuration to be semantically equivalent:

@Secured({
    "#{ true }",
    SecurityRule.IS_ANONYMOUS
})

Actual Behaviour

The following REJECTS all requests:

@Secured({
    SecurityRule.IS_ANONYMOUS,
    "#{ true }"
})

The following PERMITS all requests:

@Secured({
    "#{ true }",
    SecurityRule.IS_ANONYMOUS
})

The following REJECTS all requests, even if the user has some-role in their roles:

@Secured({
    "some-role",
    "#{ true }"
})

Reasons being:

  1. When expressions are used, only the very first result is checked - effectively dropping the OR semantic
    a. https://github.com/micronaut-projects/micronaut-security/blob/4.13.x/security/src/main/java/io/micronaut/security/rules/SecuredAnnotationRule.java#L75-L80
  2. EvaluatedAnnotationValue::booleanValues returns false for anything that is not an expression - making it impossible to mix expressions and roles/tokens within the same @Secured annotation.

Steps To Reproduce

@Controller
public class MyController {

  @Secured({"#{ true }", SecurityRule.IS_ANONYMOUS})
  @Get("/permitted")
  public void permitted() {}

  @Secured({SecurityRule.IS_ANONYMOUS, "#{ true }"})
  @Get("/rejected")
  public void rejected() {}

  @Secured({SecurityRule.IS_ANONYMOUS, "#{ false }"})
  @Get("/also-rejected")
  public void alsoRejected() {}
}
  1. Request GET /permitted
  2. Observe correct HTTP 200
  3. Request GET /rejected
  4. Observe faulty HTTP 403
  5. Request GET /also-rejected
  6. Observe faulty HTTP 403

Environment Information

No response

Example Application

No response

Version

4.8.2

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

Status
Backlog

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions