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.42k stars 4.02k forks source link

OIDC proxy error on port 9000 or 4200, when using infinispan caching, yet it works when not proxying on port 8080 #26358

Open naris opened 2 months ago

naris commented 2 months ago
Overview of the issue

When using an external OIDC provider (keycloak) running a newly generated jhipster app, after setting the issuer-uri to the keycloak server, the application works if you go directly to the app on port 8080 but if you use the proxy on port 9000, or 4200, it errors out with "Error occurred while trying to proxy: localhost:9000/oauth2/authorization/oidc"

I have this issue with my existing project, which is where I encountered it after upgrading to jhipster 8.x, but it also happens with a newly generated project. This worked before when using jhipster 7.x

Motivation for or Use Case

To be able to use the BrowserStack proxy/HMR. I am able to work around the issue by going directly to port 8080 and not running npm start, but that is not how one is supposed to develop a jhipster app :(

Reproduce the error
  1. Generate a jhipster application using oauth2/openapi authentication, you can either use the .yo-rc.json in this issue or generate a new application by answering the jhipster questions, specifying oauth2/oidc authentication.
  2. set up or use an existing non-local keycloak provider on a different machine
  3. set security:oauth2:client:provider:oidc:issuer-uri: https:///realms/ in application.yml
  4. comment out or remove offline_access from security:oauth2:client:provider:registration:oidc:scope in application.yml
  5. start the application itself with ./mvnw
  6. go to the application's port (localhost:8080) and click sign-in, this will work
  7. start the BrowserStack proxy by running npm start (which also automagically goes to localhost:9000 in your browser)
  8. go to the proxied port (localhost:9000), if not already there, and click sign-in, this will not work and show "Error occurred while trying to proxy: localhost:9000/oauth2/authorization/oidc"
Related issues
Suggest a Fix
JHipster Version(s)

8.3.0 & 8.5.0

JHipster configuration
.yo-rc.json file
{
  "generator-jhipster": {
    "applicationType": "monolith",
    "authenticationType": "oauth2",
    "baseName": "TotalFact",
    "buildTool": "maven",
    "cacheProvider": "infinispan",
    "clientFramework": "angular",
    "clientTestFrameworks": [
      "cypress"
    ],
    "clientTheme": "none",
    "creationTimestamp": 1712780550560,
    "cypressAudit": true,
    "cypressCoverage": true,
    "databaseType": "sql",
    "devDatabaseType": "oracle",
    "devServerPort": 4200,
    "enableHibernateCache": true,
    "enableSwaggerCodegen": true,
    "enableTranslation": true,
    "entities": [
      "Attribute",
      "Category",
      "Derivation",
      "Dimension",
      "EpsilonDataSource",
      "FieldValue",
      "Platform",
      "PlatformDE",
      "PlatformInst",
      "PlatformList",
      "PlatformType",
      "PrivateNotes",
      "Product",
      "ProtectedClass",
      "Release",
      "Royalty",
      "Section",
      "SourceType",
      "Step",
      "Task",
      "Universe",
      "UPC",
      "UPCRule",
      "Usage"
    ],
    "feignClient": null,
    "jhipsterVersion": "8.3.0",
    "languages": [
      "en"
    ],
    "lastLiquibaseTimestamp": 1715294100000,
    "messageBroker": false,
    "microfrontend": null,
    "microfrontends": [],
    "nativeLanguage": "en",
    "packageName": "com.epsilon.totalfact",
    "prodDatabaseType": "oracle",
    "reactive": false,
    "searchEngine": false,
    "serverPort": null,
    "serverSideOptions": [
      "enableSwaggerCodegen:true"
    ],
    "serviceDiscoveryType": false,
    "skipCheckLengthOfIdentifier": true,
    "skipUserManagement": true,
    "syncUserWithIdp": false,
    "testFrameworks": [
      "gatling",
      "cypress"
    ],
    "websocket": false,
    "withAdminUi": true
  }
}
Environment and Tools

openjdk version "17.0.6" 2023-01-17 LTS OpenJDK Runtime Environment Microsoft-7209853 (build 17.0.6+10-LTS) OpenJDK 64-Bit Server VM Microsoft-7209853 (build 17.0.6+10-LTS, mixed mode, sharing)

git version 2.40.1.windows.1

node: v18.20.1 npm: 10.5.0

'docker' command could not be found

JDL for the Entity configuration(s) entityName.json files generated in the .jhipster directory
JDL entity definitions
@ChangelogDate("20240509223437")
@Filter
@Paginate("pagination")
entity Attribute {
  fieldLevel String maxlength(128)
  createUser String required
  createDate Instant required
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223438")
@Filter
@Paginate("pagination")
entity Category {
  name String maxlength(128) required
  createUser String required
  createDate Instant required
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223439")
@Filter
@Paginate("pagination")
entity Derivation {
  code String maxlength(10) required
  name String maxlength(128)
  description String maxlength(1024)
}
@ChangelogDate("20240509223440")
@Filter
@Paginate("pagination")
entity Dimension {
  name String maxlength(128) required
  description String
  createUser String required
  createDate Instant required
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223441")
@Filter
@Paginate("pagination")
entity EpsilonDataSource {
  name String maxlength(128)
}
@ChangelogDate("20240509223442")
@Filter
@Paginate("pagination")
entity FieldValue {
  fieldValue String maxlength(25) required
  valueDefinition String
  averageMatchRate Float min(0) max(100)
  displayOrder Integer
  activeFlag Boolean
  createUser String
  createDate Instant
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223443")
@Filter
@Paginate("pagination")
entity Platform {
  primarySymbol String maxlength(128) required
  fieldName String maxlength(250) required
  fieldDescription String maxlength(1024)
  fieldLength Integer
  fieldValue String maxlength(100)
  shortHeaderName String maxlength(10)
  longHeaderName String maxlength(200)
  inUse Boolean
  premiumField Boolean
  approvalRequired Boolean
  royalty Boolean
  token String maxlength(50)
  sasKey String maxlength(10)
  rateId String maxlength(10)
  countType String maxlength(1)
  kvp String maxlength(50)
  caseable Boolean
  sanRequired Boolean
  waiverRequired Boolean
  createUser String
  createDate Instant
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223444")
@Filter
@Paginate("pagination")
entity PlatformDE (platform_de) {
  ecapsKey Integer
  defaultValue String maxlength(10)
  usedInBilling Boolean
  displayZeroCounts Boolean
  areaFillinRequired Boolean
  createUser String
  createDate Instant
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223445")
@Filter
@Paginate("pagination")
entity PlatformInst {
  pricingFlag Boolean
  selectFlag Boolean
  outputFlag Boolean
  crosstabFlag Boolean
  createUser String
  createDate Instant
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223446")
@Filter
@Paginate("pagination")
entity PlatformList {
  pricingFlag Boolean
  selectFlag Boolean
  outputFlag Boolean
  crosstabFlag Boolean
  createUser String
  createDate Instant
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223447")
@Filter
@Paginate("pagination")
entity PlatformType {
  name String maxlength(10) required
  description String
}
@ChangelogDate("20240509223448")
@Filter
@Paginate("pagination")
entity PrivateNotes {
  noteText TextBlob
  noteDate Instant required
  createUser String
  createDate Instant
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223449")
@Filter
@Paginate("pagination")
entity Product {
  name String
  description String
  productKey Integer min(0) max(999)
  createUser String
  createDate Instant
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223450")
@Filter
@Paginate("pagination")
entity ProtectedClass {
  code Integer min(0) max(9) required
  name String maxlength(128)
  description String maxlength(1024)
}
@ChangelogDate("20240509223451")
@Filter
@Paginate("pagination")
entity Release {
  version String
  releaseDate Instant
}
@ChangelogDate("20240509223452")
@Filter
@Paginate("pagination")
entity Royalty {
  name String maxlength(10) required
  description String
}
@ChangelogDate("20240509223453")
@Filter
@Paginate("pagination")
entity Section {
  sectionKey String maxlength(10) required
  name String maxlength(128) required
  selfReported Boolean
  modeled Boolean
  thirdParty Boolean
  areaLevel Boolean
  compiled Boolean
  updatedDaily Boolean
  updatedWeekly Boolean
  updatedBiWeeekly Boolean
  updatedMonthly Boolean
  updatedSixWeeeks Boolean
  updatedQuatrerly Boolean
  updatedSemiAnnually Boolean
  createUser String
  createDate Instant
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223454")
@Filter
@Paginate("pagination")
entity SourceType {
  code String maxlength(10) required
  name String maxlength(128)
  description String maxlength(1024)
}
@ChangelogDate("20240509223455")
@Filter
@Paginate("pagination")
entity Step {
  completed Boolean
  notes TextBlob
  createUser String
  createDate Instant
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223456")
@Filter
@Paginate("pagination")
entity Task {
  name String required
  taskUser String maxlength(25) required
  taskOrder Integer
  showOnMainPage Boolean
  createUser String
  createDate Instant
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223457")
@Filter
@Paginate("pagination")
entity Universe {
  code String maxlength(10) required
  name String maxlength(128) required
}
@ChangelogDate("20240509223458")
@Filter
@Paginate("pagination")
entity UPC {
  upcKey String maxlength(15)
  name String maxlength(250) required
  description String maxlength(1024)
  dataSource TextBlob
  keywords TextBlob
  userNotes TextBlob
  restrictedResellerFlag Boolean
  hidden Boolean
  createUser String required
  createDate Instant required
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223459")
@Filter
@Paginate("pagination")
entity UPCRule (upc_rule) {
  ruleText TextBlob required
  ruleDate Instant required
  createUser String
  createDate Instant
  modifyUser String
  modifyDate Instant
}
@ChangelogDate("20240509223500")
@Filter
@Paginate("pagination")
entity Usage (jhi_usage) {
  action String required
  parm String
  user String maxlength(25) required
  dateTime Instant required
}

relationship OneToOne {
  PlatformDE{platform} to Platform{de}
  PlatformInst{platform} to Platform{install}
  PlatformList{platform} to Platform{list}
}
relationship OneToMany {
  Dimension{categories required} to Category
  Platform{values required} to FieldValue
  UPC{rules} to UPCRule{upc required}
  UPC{privateNotes} to PrivateNotes{upc required}
  UPC{platforms required} to Platform{upc required}
  UPC{steps} to Step
}
relationship ManyToOne {
  Dimension{universe} to Universe
  Platform{release} to Release
  Platform{category} to Category{platform}
  Platform{platformType} to PlatformType
  PlatformDE{section} to Section
  Product{platformType} to PlatformType
  Step{task} to Task
  UPC{attribute required} to Attribute
  UPC{category required} to Category
  UPC{protectedClass} to ProtectedClass
  UPC{epsilonDataSource} to EpsilonDataSource
  UPC{royalty} to Royalty
}
relationship ManyToMany {
  Platform{product} to Product{platform}
  UPC{sourceType} to SourceType{upc}
  UPC{derivation} to Derivation{upc}
}

search Attribute, Category, Derivation, Dimension, EpsilonDataSource, FieldValue, Platform, PlatformDE, PlatformInst, PlatformList, PlatformType, PrivateNotes, Product, ProtectedClass, Release, Royalty, Section, SourceType, Step, Task, Universe, UPC, UPCRule, Usage with no

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

Windows 11, MS Edge

mraible commented 2 months ago

That's strange, especially since the proxy should just be sending traffic from 9000 to 8080, not to your external Keycloak instance. Spring Security handles that part and it shouldn't have anything to do with npm start. I've successfully done what you're trying to do with Okta and Auth0 as the identity provider. I haven't tried putting Keycloak on a different server and trying to talk to it, but it should work the same way.

Do you have detailed steps on how to reproduce the problem? I'm looking for something like:

  1. Create an app using the .yo-rc.json in this issue.
  2. Start Keycloak, other dependencies, and then the app.
  3. Run npm run e2e to prove everything works.
  4. Check the project into GitHub.
  5. Open the repo with Gitpod and start Keycloak.
  6. Set an environment variable to override the issuer locally and point it to Gitpod.
  7. Restart the app, run npm start, it fails with the following error (screenshot below).
naris commented 2 months ago

Oh, I'm sorry -- I did indeed neglect to put actual step to reproduce the error :(

npm start doesn't really have much to do with the issue as that runs the proxy and if you go directly to the app itself, there is no need to start the proxy.

I have updated the overview -- The detailed steps would be:

  1. Generate a jhipster application using oauth2/openapi authentication, you can either use the .yo-rc.json in this issue or generate a new application by answering the jhipster questions, specifying oauth2/oidc authentication.
  2. set up or use an existing non-local keycloak provider on a different machine
  3. set security:oauth2:client:provider:oidc:issuer-uri: https:///realms/ in application.yml
  4. comment out or remove offline_access from security:oauth2:client:provider:registration:oidc:scope in application.yml
  5. start the application itself with ./mvnw
  6. go to the application's port (localhost:8080) and click sign-in, this will work
  7. start the BrowserStack proxy by running npm start (which also automagically goes to localhost:9000 in your browser)
  8. go to the proxied port (localhost:9000), if not already there, and click sign-in, this will not work and show "Error occurred while trying to proxy: localhost:9000/oauth2/authorization/oidc"
naris commented 2 months ago

@mraible , Sorry I did not put the critical step above, I have added it. The problem does not occur when starting the app, it starts just fine. The issue is when someone tries to log in to the app -- that is when it fails and returns the error in the browser.

Error occurred while trying to proxy: localhost:9000/oauth2/authorization/oidc

The npm start session will also have this error:

[webpack-dev-server] [HPM] Error occurred while proxying request localhost:9000/oauth2/authorization/oidc to http://localhost:8080/ [ECONNREFUSED] (https://nodejs.org/api/errors.html#errors_common_system_errors)
naris commented 2 months ago

Oh, you also have to comment out offline_access from the scope or you will get a different weird error (even from port 8080) when attempting to sign in security:oauth2:client:provider:registration:oidc:scope: openid, profile, email # , offline_access # last one for refresh tokens

If offline_access is in scope, after signing in with keycloak, it will be redirected to http://localhost:8080/?error= instead of being logged in :(

mraible commented 2 months ago

I tried to reproduce this issue with the generated oauth2 sample app:

https://github.com/jhipster/jhipster-sample-app-oauth2

I cloned it locally and started everything. Then, I confirmed npm run e2e works, as well as npm start and port 9000.

I had to patch the MySQL Docker Compose file with this fix to get it to start. https://github.com/jhipster/generator-jhipster/pull/26359

Then, I cloned it on gitpod.io and started Keycloak. I changed the issuer in application-dev.yml to use it:

https://9443-jhipster-jhipstersample-7uuy7dzyae4.ws-us114.gitpod.io/realms/jhipster

And restarted JHipster. That’s when I got an error and was unable to figure out HTTP/HTTPS on Gitpod.

However, it made me wonder: is your Keycloak instance on the other server a JHipster-populated instance? Or is it a Keycloak instance that doesn’t have the jhipster realm configured?

naris commented 2 months ago

@mraible , no it is not a jhipster-populated instance nor is it in a docker container. We setup a standalone keycloak server and the server doesn't have a jhipster realm, we use the name of the application instead, total-facts, for the realm. Which is why we set the issuer-uri to https://keycloak-dev.abacus-us.com/realms/total_facts for our server. This instance always works when going directly to port 8080, it is only when going to port 9000 that logging in doesn't work. This same instance worked for a couple years, even when going to the proxy port of 9000, before we migrated to jhipster 8.x.

mraible commented 2 months ago

You probably need to configure the web origins in your standalone instance to match what JHipster's Keycloak has. I don't recommend using asterisks (*) because OAuth 2.1 doesn't allow them, but if you match these settings, you should be able to get things working the same as with your JHipster instance.

Screenshot 2024-06-05 at 1 38 39 PM
naris commented 2 months ago

We have had those settings for a long time, except for the postman one: image

naris commented 2 months ago

Again, the problem is only when proxying through BrowserStack on port 9000, not when going directly to the application on port 8080 with the version of the application updated to jhipster 8.x The old version of the application still using jhipster v7.x has no issues.

mraible commented 2 months ago

I assume you mean Browsersync, not BrowserStack? If so, does using the version of Browsersync from your 7.x project fix the problem? If not, I'm not sure what's causing the problem.

naris commented 2 months ago

Yeah, Browsersync. The odd thing now is that it works with the generated oauth2 sample app from github yet it doesn't work with the app I generated. I initially ran into this issue with my project that was migrated from jhipster 7.x to 8.x so I generated an app with Jhipster 8.3.0 (which was the current version at the time) and it didn't work. I have since generated it again with 8.5.0 and that does not work either. I am using some different settings including, Oracle prod & dev DB, Infinispan caching, openapi, Gatling. I am looking into generating with different options to see what works and what doesn't

Welcome to JHipster v8.5.0


Documentation for creating an application is at https://www.jhipster.tech/creating-an-app/

Application files will be generated in folder: C:\src\totalfact.new-3


? What is the base name of your application? TotalFact ? Which type of application would you like to create? Monolithic application (recommended for simple projects) ? What is your default Java package name? com.epsilon.totalfact ? Would you like to use Maven or Gradle for building the backend? Maven ? Do you want to make it reactive with Spring WebFlux? No ? Which type of authentication would you like to use? OAuth 2.0 / OIDC Authentication (stateful, works with Keycloak and Okta) ? Do you want to allow relationships with User entity? Yes ? Besides JUnit, which testing frameworks would you like to use? Gatling ? Which type of database would you like to use? SQL (H2, PostgreSQL, MySQL, MariaDB, Oracle, MSSQL) ? Which production database would you like to use? Oracle ? Which development database would you like to use? Oracle ? Which cache do you want to use? (Spring cache abstraction) Infinispan (hybrid cache, for multiple nodes) ? Do you want to use Hibernate 2nd level cache? Yes ? Which other technologies would you like to use? API first development using OpenAPI-generator ? Which framework would you like to use for the client? Angular ? Besides Jest/Vitest, which testing frameworks would you like to use? Cypress ? Do you want to generate the admin UI? Yes ? Would you like to use a Bootswatch theme (https://bootswatch.com/)? Default JHipster WARNING! Could not fetch bootswatch themes from API. Using default ones. ? Would you like to enable internationalization support? Yes ? Please choose the native language of the application English ? Please choose additional languages to install ? Would you like to generate code coverage for Cypress tests? [Experimental] Yes ? Would you like to audit Cypress tests? Yes

naris commented 2 months ago

@mraible, I have found that if I generate a new project with the default ehcahe caching, then it works. However, if I generate the project with everything the same, except for using infinispan caching, then attempting to log in through the port 9000 proxy fails with the "Error occurred while trying to proxy: localhost:9000/oauth2/authorization/oidc" browser error screen.