jhipster / generator-jhipster

JHipster is a development platform to quickly generate, develop, & deploy modern web applications & microservice architectures.
https://www.jhipster.tech
Apache License 2.0
21.55k stars 4.02k forks source link

Spring security + Keycloak = access denied infinite loop #25674

Closed IShostak closed 6 months ago

IShostak commented 7 months ago
Overview of the issue

Spring security + Keycloak = access denied infinite loop

Motivation for or Use Case

Basic security setup with annotation doesn't work

Reproduce the error
  1. Generate project
  2. Generate any entities
  3. Add @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")")
  4. Access the chosen endpoint without the required role (for eg. with the user)
  5. Obeserve browser stuck in an infinite loop of redirects
Related issues
Suggest a Fix
JHipster Version(s)

8.2.1

JHipster configuration
.yo-rc.json file
{
  "generator-jhipster": {
    "applicationType": "monolith",
    "authenticationType": "oauth2",
    "baseName": "testkeycloak",
    "buildTool": "maven",
    "cacheProvider": "ehcache",
    "clientFramework": "react",
    "clientTestFrameworks": [],
    "clientTheme": "quartz",
    "clientThemeVariant": "dark",
    "creationTimestamp": 1711659457012,
    "databaseType": "sql",
    "devDatabaseType": "mysql",
    "devServerPort": 9060,
    "enableGradleEnterprise": null,
    "enableHibernateCache": true,
    "enableSwaggerCodegen": false,
    "enableTranslation": true,
    "entities": [
      "Region",
      "Country",
      "Location",
      "Department",
      "Task",
      "Employee",
      "Job",
      "JobHistory"
    ],
    "feignClient": null,
    "gradleEnterpriseHost": null,
    "jhipsterVersion": "8.2.1",
    "languages": [
      "en",
      "ua"
    ],
    "lastLiquibaseTimestamp": 1711659959000,
    "messageBroker": false,
    "microfrontend": null,
    "microfrontends": [],
    "nativeLanguage": "en",
    "packageName": "com.mycompany.myapp",
    "prodDatabaseType": "mysql",
    "reactive": false,
    "searchEngine": false,
    "serverPort": null,
    "serverSideOptions": [],
    "serviceDiscoveryType": false,
    "skipUserManagement": true,
    "syncUserWithIdp": null,
    "testFrameworks": [],
    "websocket": false,
    "withAdminUi": true
  }
}
Environment and Tools

openjdk version "21.0.1" 2023-10-17 OpenJDK Runtime Environment (build 21.0.1+12-29) OpenJDK 64-Bit Server VM (build 21.0.1+12-29, mixed mode, sharing)

git version 2.43.0

node: v21.7.0 npm: 10.5.0

Docker version 25.0.3, build 4debf41

JDL for the Entity configuration(s) entityName.json files generated in the .jhipster directory
JDL entity definitions
@ChangelogDate("20240328210552")
entity Region {
  regionName String
}
@ChangelogDate("20240328210553")
entity Country {
  countryName String
}
/**
 * not an ignored comment
 */
@ChangelogDate("20240328210554")
entity Location {
  streetAddress String
  postalCode String
  city String
  stateProvince String
}
@ChangelogDate("20240328210555")
entity Department {
  departmentName String required
}
/**
 * Task entity.\n@author The JHipster team.
 */
@ChangelogDate("20240328210556")
entity Task {
  title String
  description String
}
/**
 * The Employee entity.
 */
@ChangelogDate("20240328210557")
entity Employee {
  /**
   * The firstname attribute.
   */
  firstName String
  lastName String
  email String
  phoneNumber String
  hireDate Instant
  salary Long
  commissionPct Long
}
@ChangelogDate("20240328210558")
entity Job {
  jobTitle String
  minSalary Long
  maxSalary Long
}
@ChangelogDate("20240328210559")
entity JobHistory {
  startDate Instant
  endDate Instant
  language Language
}
enum Language {
  FRENCH,
  ENGLISH,
  SPANISH
}

relationship OneToOne {
  Country{region} to Region
  Location{country} to Country
  Department{location} to Location
  JobHistory{job} to Job
  JobHistory{department} to Department
  JobHistory{employee} to Employee
}
relationship OneToMany {
  /**
   * A relationship
   */
  Department{employee} to Employee
  Employee{job} to Job
}
relationship ManyToOne {
  Employee{manager} to Employee
}
relationship ManyToMany {
  Job{task(title)} to Task{job}
}

service Region, Country, Location, Department, Task, JobHistory with serviceImpl
search Region, Country, Location, Department, Task, Employee, Job, JobHistory with no
paginate Employee, JobHistory with infinite-scroll
paginate Job with pagination

Entity configuration(s) entityName.json files generated in the .jhipster directory
Browsers and Operating System

Mac OS Sonoma, Chrome

mraible commented 6 months ago

I was able to reproduce this issue with @PreAuthorize("hasRole('ADMIN')") and @PreAuthorize("hasAuthority('ROLE_ADMIN')"). If I change the web framework to Angular in .yo-rc.json and re-generate everything, it works as expected.

Screenshot 2024-04-29 at 12 35 23 PM

It's possible React needs a similar fix that @atomfrede did for Angular to fix https://github.com/jhipster/generator-jhipster/issues/24396.

mraible commented 6 months ago

I decided to try it with Vue, but ran into an issue with the theme:

NFO] Error: Can't find stylesheet to import.
[INFO]   ╷
[INFO] 9 │ @import 'bootswatch/dist/quartz/variables';
[INFO]   │         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[INFO]   ╵
[INFO]   src/main/webapp/content/scss/vendor.scss 9:9  root stylesheet

To workaround this bug, I deleted the following from .yo-rc.json and re-generated the app:

"clientTheme": "quartz",
"clientThemeVariant": "dark",

Vue handles it properly as well.

Screenshot 2024-04-29 at 12 43 44 PM
BrayanMnz commented 6 months ago

Can you upload a sample project with the issue @mraible in order for me to take a look into it

mraible commented 6 months ago

@BrayanMnz I generated one using jhipster jdl blog-oauth2, then modified the BlogResource to have the @PreAuthorize annotation on its getAllBlogs() method.