Skip to content
This repository has been archived by the owner on Feb 23, 2023. It is now read-only.

Property or field 'idToken' cannot be found on object of type 'org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser' - maybe not public or not valid? #1378

Closed
mraible opened this issue Dec 14, 2021 · 13 comments
Assignees
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged or decided on

Comments

@mraible
Copy link

mraible commented Dec 14, 2021

I'm trying to get a JHipster-generated Spring MVC app to work with the latest version of Spring Native. When the user tries to log out, the following error shows up in the logs and logout fails.

org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'idToken' cannot be found on 
object of type 'org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser' - maybe not public or not valid?
        at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:217) ~[na:na]
        at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:104) ~[na:na]
        at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:91) ~[na:na]
        at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:112) ~[na:na]
        at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:272) ~[na:na]
        at org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver.resolveArgument(AuthenticationPrincipalArgumentResolver.java:116) ~[na:na]

I tried adding a @TypeHint for DefaultOidcUser.class, but that doesn't help. Here's my method signature:

@PostMapping("/api/logout")
public ResponseEntity<?> logout(HttpServletRequest request, @AuthenticationPrincipal(expression = "idToken") OidcIdToken idToken) { }

Another error that happens is:

java.lang.IllegalArgumentException: Name for argument of type [boolean] not specified, and parameter name information not found in class file either.
        at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.updateNamedValueInfo(AbstractNamedValueMethodArgumentResolver.java:177) ~[na:na]
        at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.getNamedValueInfo(AbstractNamedValueMethodArgumentResolver.java:154) ~[na:na]
        at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:99) ~[na:na]
        at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[na:na]
        at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179) ~[na:na]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146) ~[na:na]

The method signature for this class is:

@GetMapping("/posts")
public ResponseEntity<List<Post>> getAllPosts(
    @org.springdoc.api.annotations.ParameterObject Pageable pageable,
    @RequestParam(required = false, defaultValue = "false") boolean eagerload
) { }

I tried adding org.springdoc.api.annotations.ParameterObject.class to @TypeHints, but that doesn't help. I also tried adding the native springdocs dependency.

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-native</artifactId>
    <version>1.6.0</version>
</dependency>

To reproduce this issue, perform the following steps:

git clone -b spring-native-0.11 [email protected]:mraible/spring-native-examples.git
cd spring-native-examples/postgres-mvc
./mvnw package -Pnative,prod -DskipTests

When the process completes, start Keycloak and PostgreSQL:

docker-compose -f src/main/docker/keycloak.yml up -d
docker-compose -f src/main/docker/postgresql.yml up -d
./target/postgres-mvc

Open a browser to http://localhost:8080 and log in with admin/admin. Then try to log out. You'll see the first error about DefaultOidcUser in the logs. Then, navigate to Entities > Post and you'll see the 2nd error.

/cc @joshlong

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Dec 14, 2021
@mraible
Copy link
Author

mraible commented Dec 14, 2021

I was able to fix the 2nd issue by adding a name to the @RequestParam annotation:

@RequestParam(name = "eagerload", required = false, defaultValue = "false") boolean eagerload

I noticed something similar when I try to edit a post:

java.lang.IllegalArgumentException: Name for argument of type [java.lang.Long] not specified, and parameter 
name information not found in class file either.

The method signature is:

public ResponseEntity<Post> getPost(@PathVariable Long id) {

Changing it to the following solves the problem:

public ResponseEntity<Post> getPost(@PathVariable("id") Long id) {

Thanks to this blog post for helping me figure this out.

After making these changes, I discovered a new issue. If I try to update an entity with a many-to-many relationship to another entity, it fails with:

org.springframework.http.converter.HttpMessageConversionException: Type definition error: 
[collection type; class java.util.HashSet, contains [simple type, class java.lang.Object]]; 
nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
Cannot construct instance of `java.util.HashSet` (no Creators, like default constructor, exist): 
no default no-arguments constructor found
 at [Source: (PushbackInputStream); line: 1, column: 137] (through reference chain: 
com.mycompany.myapp.domain.Post["tags"])

You can see my Post entity here.

@mraible
Copy link
Author

mraible commented Dec 14, 2021

I was able to fix the initial issue by removing (expression = "idToken") and just getting the OidcUser.

public ResponseEntity<?> logout(HttpServletRequest request, @AuthenticationPrincipal OidcUser oidcUser) {

Should I keep this one open for the HttpMessageConversionException or open a new one for that?

@sdeleuze
Copy link
Contributor

I was able to fix the initial issue by removing (expression = "idToken") and just getting the OidcUser.

Could you please let me know if the original issue is native specific or also happen on the JVM with the AOT mode enabled?

Should I keep this one open for the HttpMessageConversionException or open a new one for that?

Please create another issue for the HttpMessageConversionException error, I think we only configure class reflection and need to configure constructors reflection as well for Java types.

@mraible
Copy link
Author

mraible commented Dec 17, 2021

Could you please let me know if the original issue is native specific or also happen on the JVM with the AOT mode enabled?

It happens in JVM mode. I didn't test AOT-mode enabled. I can do that, as well as enter a new issue when I'm back from vacation in January. Happy holidays!

@sdeleuze
Copy link
Contributor

sdeleuze commented Dec 20, 2021

Looks like to me you miss the -parameters javac parameter (if wrong, please reopen), so I will close that one and let you create the other one for HttpMessageConversionException when you are back. Happy holidays too.

@sdeleuze sdeleuze added status: invalid An issue that we don't feel is valid and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Dec 20, 2021
@mraible
Copy link
Author

mraible commented Feb 4, 2022

Looks like to me you miss the -parameters javac parameter

Sorry for commenting on a closed issue, just getting back to this now. I tried with JHipster 7.6.0 today, which uses Spring Boot v2.6.3 today.

I'm not sure where -parameters should be passed in. I'm just building my apps with the following command:

./mvnw package -Pnative,prod -DskipTests

I still have an issue using (expression = "idToken") in a method signature. This fails:

public ResponseEntity<?> logout(HttpServletRequest request, 
  @AuthenticationPrincipal(expression = "idToken") OidcIdToken idToken) {

This works:

public ResponseEntity<?> logout(HttpServletRequest request, 
  @AuthenticationPrincipal OidcUser oidcUser) {

    ...
    OidcIdToken idToken = oidcUser.getIdToken();

Other things I noticed:

  1. If I run ./mvnw package -Pnative (without skipping tests) on a WebFlux app, I get a cryptic errors:
[ERROR] Failed to execute goal org.springframework.experimental:spring-aot-maven-plugin:0.11.2:test-generate (test-generate) on project jhipster:
Build failed during Spring AOT test code generation: Unable to execute mojo:
Unable to parse configuration of mojo org.apache.maven.plugins:maven-compiler-plugin:3.9.0:testCompile for parameter compilePath:
Cannot find 'compilePath' in class org.apache.maven.plugin.compiler.TestCompilerMojo -> [Help 1]
[ERROR]

If I run the same command on an MVC app, I get a better error message:

Caused by: java.lang.IllegalStateException: @MockBean is not supported yet by Spring AOT
and has been detected on type org.springframework.web.client.RestTemplate

Both projects use Mockito.

  1. I've always had to add type hints for Micrometer. I'm guessing there are plans to add these by default for Spring Boot 3?
@TypeHint(
    types = {
        org.HdrHistogram.Histogram.class,
        org.HdrHistogram.ConcurrentHistogram.class
    })
  1. If I'm using MVC + JPA, and I've added the Hibernate plugin, I have to turn off loading of SQL so Liquibase works:
spring:
  ...
  sql:
    init:
      mode: never

Without this change, the following error happens:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceScriptDatabaseInitializer':
Circular depends-on relationship between 'dataSourceScriptDatabaseInitializer' and 'liquibase'
  1. I'm still seeing an error with R2DBC repositories.

  2. JPA doesn't allow saving entities that have relationships.

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Unable to perform requested lazy initialization
[com.mycompany.myapp.domain.Post.tags] - no session and settings disallow loading outside the Session
(through reference chain: java.util.Collections$UnmodifiableRandomAccessList[0]->com.mycompany.myapp.domain.Post["tags"])

@sdeleuze sdeleuze reopened this Feb 4, 2022
@sdeleuze sdeleuze added status: waiting-for-triage An issue we've not yet triaged or decided on and removed status: invalid An issue that we don't feel is valid labels Feb 4, 2022
@sdeleuze
Copy link
Contributor

sdeleuze commented Feb 4, 2022

Hey Matt thanks for your comment, we are working with the team to provide a feedback on each point.

Are points 4 and 5 native specific (do they work on the JVM) ?

@sdeleuze sdeleuze added the status: waiting-for-feedback We need additional information before we can continue label Feb 4, 2022
@mraible
Copy link
Author

mraible commented Feb 4, 2022

Everything is native specific. All the issues I mentioned work fine on the JVM.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Feb 4, 2022
@eleftherias
Copy link
Contributor

@mraible For the original issue, Property or field 'idToken' cannot be found on object of type 'org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser', I was able to get the annotation working with the following hint:

@TypeHint(types = DefaultOidcUser.class, access = TypeAccess.PUBLIC_METHODS)

Note that I had to specify the access because the default access is not enough to evaluate the expression.

@sdeleuze
Copy link
Contributor

sdeleuze commented Feb 4, 2022

Thanks @eleftherias for sharing your findings.
I don't plan to add those hints which are too specific, so for now I would suggest to either use the annotation-less variant or to add the related hint with the customize access.

The best solution to solve this issue at the root is AOT evaluation of SpEL expression, the related issue you can follow is #167.

I am letting this issue open in order to provide a feedback on the other points raised.

@mraible
Copy link
Author

mraible commented Feb 6, 2022

Today I discovered that item 5 (JPA failing to save relationships) is a JHipster bug and is not related to Spring Native as far as I know. jhipster/generator-jhipster#17794

@mraible
Copy link
Author

mraible commented Feb 6, 2022

Regarding item 4 (R2DBC repositories don't work), I forgot about this in the docs:

Custom repository implementation fragments need to be annotated with @component.

I added @Component to each of the Impl classes, but that doesn't seem to help. I get the same error on startup:

Caused by: java.lang.IllegalStateException: No suitable constructor found on class 
org.springframework.data.r2dbc.repository.support.SimpleR2dbcRepository to match the given arguments: 
org.springframework.data.relational.repository.support.MappingRelationalEntityInformation, 
org.springframework.data.r2dbc.core.R2dbcEntityTemplate, 
org.springframework.data.r2dbc.convert.MappingR2dbcConverter. 
Make sure you implement a constructor taking these

If I add SimpleR2dbcRepository to my type hints, it works!

Here's a PR that shows the changes I had to make. mraible/spring-native-examples#7

@sdeleuze
Copy link
Contributor

sdeleuze commented Feb 8, 2022

Feeback on the other points mentioned:

  1. I tried in both webflux-netty and webmvc-tomcat with @MockBean and saw the meaningful error, so I tend to think the error you see is unrelated. If you manage to have a minimal repro with just Spring Native involved, please create a dedicated issue.
  2. Added via Add missing hints for HdrHistogram #1484
  3. Tracked via Circular depends-on relationship with Flyway and Liquibase #1480
  4. For some reasons, SimpleR2dbcRepository hints defined in R2dbcRepositoriesHints with a R2dbcRepositoriesAutoConfiguration trigger seems not taken in account in your JHipster application. I tried to reproduce in data-r2dbc sample without success. What would help would be to work on a reproducible pure Spring Native sample and create a dedicated issue once you find how to reproduce.
  5. JHipster specific based on your feedback.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged or decided on
Development

No branches or pull requests

4 participants