Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] OAuth2/OpenIDC Authentication failure #1291

Closed
ghost opened this issue Apr 24, 2020 · 11 comments
Closed

[Bug] OAuth2/OpenIDC Authentication failure #1291

ghost opened this issue Apr 24, 2020 · 11 comments
Assignees
Milestone

Comments

@ghost
Copy link

ghost commented Apr 24, 2020

Request Type

Bug

Work Environment

Question Answer
OS version (server) RedHat
OS version (client) Windows 10
TheHive version / git hash 3.4.1
Package Type Docker
Browser type & version Chrome 81.0

Problem Description

oauth 2 configured in config file
ssologin appears on the TheHive login screen
Clicked the ssologin button
Request URL: https://<the-hive-url>/api/ssoLogin
Status code: 200 OK
Request URL: https://<adfs-url>/adfs/oauth2/authorize?scope=openid&response_type=code&redirect_uri=https%3A%2F%2F<the-hive-url>%2Foauth2&client_id=<clientid-secret-value>
Status code: 302 Found
Request URL: https://<the-hive-url>/oauth2?code=<the-value-of-the-code>
Status code: 302 Moved Temporarily
Request URL: https://<the-hive-url>/api/ssoLogin?code=<the-value-of-the-code>
Status code: 401 Unauthorized

That latest POST request https:///api/ssoLogin?code= returned 401

Since our ADFS does not support the "#" in the url we used the rewrite see documentation
documentation: Redirect "/redirect_uri" "/index.html#!/login"
configuratiuon: Redirect "/oauth2" "/index.html#!/login"

Complementary information

[error] o.e.s.a.MultiAuthSrv - Authentication failure org.elastic4play.AuthenticationError: Unexpected response from server: 401 at services.OAuth2Srv.$anonfun$getAuthTokenAndAuthenticate$6(OAuth2Srv.scala:122) at scala.concurrent.Future.$anonfun$flatMap$1(Future.scala:303) at scala.concurrent.impl.Promise.$anonfun$transformWith$1(Promise.scala:37) at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60) at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:55) at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:91) at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12) at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:81) at akka.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:91) at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40) [info] o.e.ErrorHandler - POST /api/ssoLogin?code=<the-value-of-the-code> returned 401 org.elastic4play.AuthenticationError: Authentication failure at org.elastic4play.services.auth.MultiAuthSrv$$anonfun$authenticate$6.applyOrElse(MultiAuthSrv.scala:71) at org.elastic4play.services.auth.MultiAuthSrv$$anonfun$authenticate$6.applyOrElse(MultiAuthSrv.scala:67) at scala.concurrent.Future.$anonfun$recoverWith$1(Future.scala:413) at scala.concurrent.impl.Promise.$anonfun$transformWith$1(Promise.scala:37) at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60) at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:55) at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:91) at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12) at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:81) at akka.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:91)

@ghost ghost added the bug label Apr 24, 2020
@ghost ghost changed the title OAuth2/OpenIDC Authentication failure [BUG] OAuth2/OpenIDC Authentication failure Apr 24, 2020
@ghost ghost changed the title [BUG] OAuth2/OpenIDC Authentication failure [Bug] OAuth2/OpenIDC Authentication failure Apr 24, 2020
@To-om
Copy link
Contributor

To-om commented Apr 24, 2020

This problem is probably related to #1228.
TheHive gets an unauthorized error (Unexpected response from server: 401) when it requests the userUrl with the bearer token. According to the RFC6750, the term "Bearer" must be capitalized.

@ghost
Copy link
Author

ghost commented Apr 24, 2020

We are currently on version 3.4.1-1 info from https://<the-hive-url>/api/status

We looked at the class file org.thehive-project.thehivebackend-3.4.1-1\services\OAuth2Srv.class and the Authorization header (Bearer) is already with a capital B ...

Any other idea @To-om ?

@To-om
Copy link
Contributor

To-om commented Apr 24, 2020

Before 3.4.1, authorization header contains "bearer" (not capitalized). I think that your OAuth server doesn't accept capitalized "bearer"

@ghost
Copy link
Author

ghost commented Apr 24, 2020

@To-om seems that the bearer or Bearer token is fine ..
After troubleshooting we noticed that ADFS 4.0 expects a resource parameter in the authorize request.
Still we are facing issue with Elastic4playAuthenticationError User info failes

@To-om To-om self-assigned this Apr 25, 2020
@To-om
Copy link
Contributor

To-om commented Apr 25, 2020

Can you share your OAuth2 configuration (without secrets) ?
Can you also enable debug messages : uncomment the following lines in /etc/logback.xml:

    <logger name="org.elastic4play.services.auth" level="DEBUG" />
    <logger name="services.OAuth2Srv" level="DEBUG" />
    <logger name="services.mappers" level="DEBUG" />

@ghost
Copy link
Author

ghost commented Apr 27, 2020

@To-om

This is the redacted OAuth config ...
As I mentioned it seems that the ADFS 4 needs an additional parameter in the authorizationUrl
That is why we added ?resource=urn:microsoft:userinfo at the end of that line.

The DEBUG level was already activated on our instance ...

oauth2 {
           # URL of the authorization server
           clientId = "<REDACTED>"
           clientSecret = "<REDACTED>"
           redirectUri = "https://<the-hive-url>/oauth2"
           #redirectUri = "https://<the-hive-url>/index.html"
           responseType = "code"
           grantType = "authorization_code"

           # URL from where to get the access token
           authorizationUrl = "https://<the-adfs-url>/adfs/oauth2/authorize?resource=urn:microsoft:userinfo"
           tokenUrl = "https://<the-adfs-url>/adfs/oauth2/token"

           # The endpoint from which to obtain user details using the OAuth token, after successful login
           userUrl = "https://<the-adfs-url>/adfs/userinfo"
           scope = "openid"
       }

       # Single-Sign On
       sso {
           # Autocreate user in database?
           autocreate = true

           # Autoupdate its profile and roles?
           autoupdate = true

           # Autologin user using SSO?
           autologin = false
           # Attributes mappings
           attributes {
             login = "winaccountname"
             name = "display_name"
           #  groups = "group"
             roles = "group"
           }

           # Name of mapping class from user resource to backend user ('simple' or 'group')
           mapper = simple
           # Default roles for users with no groups mapped ("read", "write", "admin")
           defaultRoles = ["read"]

       #    groups {
             # URL to retreive groups (leave empty if you are using OIDC)
             # Group mappings, you can have multiple roles for each group: they are merged
       #      mappings {
       #        admin = ["admin"]
       #        write = ["write"]
       #        read = ["read"]
       #      }
       #    }
       }

@ghost
Copy link
Author

ghost commented Apr 27, 2020

De error message in the log file

[debug] o.e.s.a.MultiAuthSrv - key AuthenticationError SS... 
[debug] o.e.s.a.MultiAuthSrv - key AuthenticationError SSO authentication is not supported
[debug] o.e.s.a.MultiAuthSrv - local AuthenticationError SSO authentication is not supported
[debug] o.e.s.a.MultiAuthSrv - ldap AuthenticationError SSO authentication is not supported
[debug] o.e.s.a.MultiAuthSrv - oauth2 OAuth2Redirect https://<adfs-url>/adfs/oauth2/authorize?resource=urn:microsoft:userinfo
[debug] o.e.s.a.MultiAuthSrv - key AuthenticationError SSO authentication is not supported
[debug] o.e.s.a.MultiAuthSrv - local AuthenticationError SSO authentication is not supported
[debug] o.e.s.a.MultiAuthSrv - ldap AuthenticationError SSO authentication is not supported
[debug] s.OAuth2Srv - Getting user token with the code from the response
[debug] s.OAuth2Srv - Getting user info using access token
[error] o.e.s.a.MultiAuthSrv - Authentication failure
org.elastic4play.AuthenticationError: User info fails: 'samaccountname' is undefined on object: {"sub":"x<redacted>="}
        at services.mappers.SimpleUserMapper.getUserFields(SimpleUserMapper.scala:40)
        at services.mappers.MultiUserMapperSrv.getUserFields(MultiUserMapperSrv.scala:27)
        at services.OAuth2Srv.$anonfun$getOrCreateUser$1(OAuth2Srv.scala:138)
        at scala.Option.fold(Option.scala:158)
        at services.OAuth2Srv.withOAuth2Config(OAuth2Srv.scala:80)
        at services.OAuth2Srv.getOrCreateUser(OAuth2Srv.scala:137)
        at services.OAuth2Srv.$anonfun$getAuthTokenAndAuthenticate$6(OAuth2Srv.scala:125)
        at scala.concurrent.Future.$anonfun$flatMap$1(Future.scala:303)
        at scala.concurrent.impl.Promise.$anonfun$transformWith$1(Promise.scala:37)
        at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
[debug] o.e.s.a.MultiAuthSrv - oauth2 AuthenticationError User info fails: 'samaccountname' is undefined on object: {"sub":"x<redacted>="}
[info] o.e.ErrorHandler - POST /api/ssoLogin?code=<redacted> returned 401
org.elastic4play.AuthenticationError: Authentication failure
        at org.elastic4play.services.auth.MultiAuthSrv$$anonfun$authenticate$6.applyOrElse(MultiAuthSrv.scala:71)
        at org.elastic4play.services.auth.MultiAuthSrv$$anonfun$authenticate$6.applyOrElse(MultiAuthSrv.scala:67)
        at scala.concurrent.Future.$anonfun$recoverWith$1(Future.scala:413)
        at scala.concurrent.impl.Promise.$anonfun$transformWith$1(Promise.scala:37)
        at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
        at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:55)
        at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:91)
        at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
        at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:81)
        at akka.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:91) 

@hkelley
Copy link

hkelley commented Apr 28, 2020

My log looks similar, though my error from the IDP is slightly different (I'm not on ADFS). I get " oauth2 AuthenticationError unexpected response from server: 400" instead of the samaccountname error. My IDP's logs show a success grant of an oauth2 access token. I assume this means that it is failing when calling the /userinfo endpoint.

2020-04-28 03:23:33,072 [DEBUG] from org.elastic4play.services.auth.MultiAuthSrv in application-akka.actor.default-dispatcher-2 - key AuthenticationError SSO authentication is not supported
2020-04-28 03:23:33,072 [DEBUG] from services.OAuth2Srv in application-akka.actor.default-dispatcher-2 - Getting user token with the code from the response!
2020-04-28 03:23:33,252 [ERROR] from org.elastic4play.services.auth.MultiAuthSrv in application-akka.actor.default-dispatcher-20 - Authentication failure
org.elastic4play.AuthenticationError: unexpected response from server: 400
        at services.OAuth2Srv.$anonfun$**getAuthTokenAndAuthenticate$5(OAuth2Srv.scala:107)**
        at scala.concurrent.Future.$anonfun$flatMap$1(Future.scala:303)
        at scala.concurrent.impl.Promise.$anonfun$transformWith$1(Promise.scala:37)
        at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
        at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:55)
        at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:91)
        at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
        at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:81)
        at akka.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:91)
        at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40)
        at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:44)
        at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
        at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
        at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
        at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
2020-04-28 03:23:33,252 [DEBUG] from org.elastic4play.services.auth.MultiAuthSrv in application-akka.actor.default-dispatcher-20 - oauth2 AuthenticationError unexpected response from server: 400
2020-04-28 03:23:33,253 [INFO] from org.elastic4play.ErrorHandler in application-akka.actor.default-dispatcher-20 - POST /api/ssoLogin?code=M......N returned 401
org.elastic4play.AuthenticationError: Authentication failure
        at org.elastic4play.services.auth.MultiAuthSrv$$anonfun$authenticate$6.applyOrElse(MultiAuthSrv.scala:71)
        at org.elastic4play.services.auth.MultiAuthSrv$$anonfun$authenticate$6.applyOrElse(MultiAuthSrv.scala:67)
        at scala.concurrent.Future.$anonfun$recoverWith$1(Future.scala:413)
        at scala.concurrent.impl.Promise.$anonfun$transformWith$1(Promise.scala:37)
        at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
        at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:55)
        at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:91)
        at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
        at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:81)
        at akka.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:91)
        at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40)
        at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:44)
        at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
        at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
        at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
        at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

@hkelley
Copy link

hkelley commented Apr 29, 2020

What's the best way to debug a call to userUrl? Based on the log statements and the 400 error returned by my IDP, I feel 99% sure this is a data format/configuration issue.

I'm not familiar enough with Scala to recompile TheHive (so that I can build in additional logging commands). Is there another way to get more visibility from the existing binaries?

@nadouani nadouani added this to the 3.5.0-RC1 milestone May 29, 2020
@1earch
Copy link

1earch commented Jun 10, 2020

@ddebast, according to your error message, you are using a TheHive version older than 3.4.1 which introduced better error logging. If you upgrade, you may be helped by a better log message. However, I think your problem is the one below:

It seems that you configured the auth.sso.attributes.login parameter to samaccountname, but this field isn't returned in the auth response {"sub":"x<redacted>="}. Thus, I see two solutions:

  • your login info is returned in the sub field, so you can configure
    auth.sso.attributes.login = "sub"
    
  • your login info is really returned in the samaccountname so your IDP must return this value. Maybe you should request it in the auth.oauth2.scope parameter? I don't know. It depends of you IDP (here ADFS 4)

Hoping I helped! 🙂

@1earch
Copy link

1earch commented Jun 10, 2020

@hkelley, according to your second log line, you are also using a TheHive version older than 3.4.1 (the ! has been deleted in 3.4.1). I recommend you to upgrade to 3.4.1 or older to have better logging on the OAuth feature.

In my opinion, your problem is a different one: your IDP is responding with a 400 HTTP error which is specified in OAuth as an error. However, it is strange that the logged ${userResponse.body} is empty. According to this doc, an error and error_description might be provided... Please check in your IDP logs to determine what error is raised on its side

To-om added a commit that referenced this issue Aug 12, 2020
@To-om To-om closed this as completed Aug 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants