Spring Cloud Data Flow security configuracion and integration with RedHat SSO

1k Views Asked by At

We are trying to turn on the security for Spring Cloud Data Flow following the documentation (https://docs.spring.io/spring-cloud-dataflow/docs/current-SNAPSHOT/reference/htmlsingle/#configuration-security) but we have some knowledge gaps that we are not capable to fill.

According to the point 9.2, it is possible to configure the authentication with OAuth 2.0 and integrate it with SSO. We use RedHat SSO, so we are trying to integrate both of them, but we are not capable to make it works, is it possible or there is a limitation about the SSO used?

Following the documentation, we have set these properties:

  • spring.security.oauth2.client.registration.uaa.client-id=xxxxxxx
  • spring.security.oauth2.client.registration.uaa.client-secret=xxxxxx
  • spring.security.oauth2.client.registration.uaa.redirect-uri='{baseUrl}/login/oauth2/code/{registrationId}'
  • spring.security.oauth2.client.registration.uaa.authorization-grant-type=authorization_code
  • spring.security.oauth2.client.registration.uaa.scope[0]=openid
  • spring.security.oauth2.client.provider.uaa.jwk-set-uri=../openid-connect/certs
  • spring.security.oauth2.client.provider.uaa.token-uri=../openid-connect/token
  • spring.security.oauth2.client.provider.uaa.user-info-uri=../openid-connect/userinfo
  • spring.security.oauth2.client.provider.uaa.user-name-attribute=user_name
  • spring.security.oauth2.client.provider.uaa.authorization-uri=../openid-connect/auth
  • spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=../openid-connect/token/introspect
  • spring.security.oauth2.resourceserver.opaquetoken.client-id=xxxxxxx
  • spring.security.oauth2.resourceserver.opaquetoken.client-secret=xxxxxxx

So we have some considerations:

  • The properties resourceserver.opaquetoken are needed for the introspection of the token, so we are pretty sure that they are necessary for when we receive a REST request and it must have the Authorization header
  • If we are not using UAA, should the properties be named uaa?
  • When we try to access to de UI, it redirects to the authorization-uri because the authorization-grant-type=authorization_code, so it will login in the SSO, is that right?
  • If we use the grant-type Password it would request directly a username/password for login, where does it is validated?
  • The user-info URI is mandatory but, is it really used?
  • What are the other URIs (jwk and token) used for?
  • Why the redirect URI has that format? where does that variables point to?

Finally, we have test the configuration in a SCDF running in a Docker container, but it does "nothing":

dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] org.apache.tomcat.util.http.Parameters   : Set query string encoding to UTF-8
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] o.a.t.util.http.Rfc6265CookieProcessor   : Cookies: Parsing b[]: JSESSIONID=55694CBB4F694DD2E345AF61AF90B05D
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] o.a.catalina.connector.CoyoteAdapter     :  Requested cookie session id is 55694CBB4F694DD2E345AF61AF90B05D
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] o.a.c.authenticator.AuthenticatorBase    : Security checking request POST /tasks/executions
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] org.apache.catalina.realm.RealmBase      :   No applicable constraints defined
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] o.a.c.a.jaspic.AuthConfigFactoryImpl     : Loading persistent provider registrations from [/tmp/tomcat.1807897745863872641.9393/conf/jaspic-providers.xml]
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] o.a.c.authenticator.AuthenticatorBase    : Not subject to any constraint
dataflow-server    |  INFO 1 --- [nio-9393-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] o.apache.catalina.core.StandardWrapper   :   Returning non-STM instance
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] org.apache.tomcat.util.http.Parameters   : Set encoding to UTF-8
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] org.apache.tomcat.util.http.Parameters   : Start processing with input [name=microapabatch&arguments=--my.arguments.sleep=2000+--my.arguments.forceFailure=false]
dataflow-server    | TRACE 1 --- [nio-9393-exec-1] s.n.www.protocol.http.HttpURLConnection  : ProxySelector Request for https://xxxxxxxxxxxxxxxxxxxxxxxx/openid-connect/token/introspect
dataflow-server    | TRACE 1 --- [nio-9393-exec-1] s.n.www.protocol.http.HttpURLConnection  : Looking for HttpClient for URL https://xxxxxxxxxxxxxxxxxxxxxxxx/openid-connect/token/introspect and proxy value of DIRECT
dataflow-server    | TRACE 1 --- [nio-9393-exec-1] s.n.www.protocol.http.HttpURLConnection  : Creating new HttpsClient with url:https://xxxxxxxxxxxxxxxxxxxxxxxx/openid-connect/token/introspect and proxy:DIRECT with connect timeout:-1
dataflow-server    | TRACE 1 --- [nio-9393-exec-1] s.n.www.protocol.http.HttpURLConnection  : Proxy used: DIRECT
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] o.a.tomcat.util.net.SocketWrapperBase    : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@1376a3b7:org.apache.tomcat.util.net.NioChannel@198ec8c7:java.nio.channels.SocketChannel[connected local=/172.18.0.4:9393 remote=/172.18.0.1:33758]], Read from buffer: [0]
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] org.apache.tomcat.util.net.NioEndpoint   : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@1376a3b7:org.apache.tomcat.util.net.NioChannel@198ec8c7:java.nio.channels.SocketChannel[connected local=/172.18.0.4:9393 remote=/172.18.0.1:33758]], Read direct from socket: [0]
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] o.apache.coyote.http11.Http11Processor   : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@1376a3b7:org.apache.tomcat.util.net.NioChannel@198ec8c7:java.nio.channels.SocketChannel[connected local=/172.18.0.4:9393 remote=/172.18.0.1:33758]], Status in: [OPEN_READ], State out: [OPEN]
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] o.a.coyote.http11.Http11NioProtocol      : Pushed Processor [org.apache.coyote.http11.Http11Processor@17492586]
dataflow-server    | DEBUG 1 --- [nio-9393-exec-1] org.apache.tomcat.util.net.NioEndpoint   : Registered read interest for [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@1376a3b7:org.apache.tomcat.util.net.NioChannel@198ec8c7:java.nio.channels.SocketChannel[connected local=/172.18.0.4:9393 remote=/172.18.0.1:33758]]

It seems that the problem is the 'remote=/172.18.0.1:33758', but we can't explain how the introspect uri can be converted in this local IP.

2

There are 2 best solutions below

0
On BEST ANSWER

For those as newbie as I was, I am going to add some points to take into account when configuring the security in SCDF

First, some comments to the original considerations:

  • The properties resourceserver.opaquetoken are needed for the introspection of the token, so we are pretty sure that they are necessary for when we receive a REST request and it must have the Authorization header --> That is.
  • If we are not using UAA, should the properties be named uaa? --> It is just a label, you can put whatever you want. It creates the relationship between all the related properties and is the text that appears in the page for login.
  • When we try to access to de UI, it redirects to the authorization-uri because the authorization-grant-type=authorization_code, so it will login in the SSO, is that right? --> Yes, this shows a page with the label (link) used in the previous point that redirect to your SSO login page.
  • If we use the grant-type Password it would request directly a username/password for login, where does it is validated? --> In older versions of SCDF it was possible to set usernames and passwords directly in the config file, but this is not available anymore. I have not continued investigating this option since with the authorization_code we made it work.
  • The user-info URI is mandatory but, is it really used? --> Yes, it is used in a point of the authentication flow.
  • What are the other URIs (jwk and token) used for? --> Are part of the authentication flow
  • Why the redirect URI has that format? where does that variables point to? --> Once you are authenticated, you are redirected to this url, where 'baseUrl' is your hostname and it is automatically resolved.

Now, the configuration we used to make it work:

  • spring.security.oauth2.client.registration.RedHatSSO.client-id=XXXXXXX
  • spring.security.oauth2.client.registration.RedHatSSO.client-secret=YYYYYYY
  • spring.security.oauth2.client.registration.RedHatSSO.redirect-uri={baseUrl}/login/oauth2/code/{registrationId} --> Beware of the feet mark symbols (') enclosing the value, they are necessary or not depending on the infraestructure used for the deployment.
  • spring.security.oauth2.client.registration.RedHatSSO.authorization-grant-type=authorization_code
  • spring.security.oauth2.client.registration.RedHatSSO.scope[0]=openid
  • spring.security.oauth2.client.provider.RedHatSSO.user-name-attribute=preferred_username --> This property is necessary to indicate the label of the property where the user name is located in the response of the SSO server (when it is not 'username').
  • spring.security.oauth2.client.provider.RedHatSSO.jwk-set-uri=https://ZZZZZZZZZZZZ/protocol/openid-connect/certs --> All these endpoint URIs should be set according to the endpoints provided by the SSO.
  • spring.security.oauth2.client.provider.RedHatSSO.token-uri=https://ZZZZZZZZZZZZ/protocol/openid-connect/token
  • spring.security.oauth2.client.provider.RedHatSSO.user-info-uri=https://ZZZZZZZZZZZZ/protocol/openid-connect/userinfo
  • spring.security.oauth2.client.provider.RedHatSSO.authorization-uri=https://ZZZZZZZZZZZZ/protocol/openid-connect/auth
  • spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://ZZZZZZZZZZZZ/protocol/openid-connect/token/introspect
  • spring.security.oauth2.resourceserver.opaquetoken.client-id=XXXXXXX
  • spring.security.oauth2.resourceserver.opaquetoken.client-secret=YYYYYYY
  • spring.cloud.dataflow.security.authorization.provider-role-mappings.RedHatSSO.map-oauth-scopes=true --> Activates the role mapping configuration
  • spring.cloud.dataflow.security.authorization.provider-role-mappings.RedHatSSO.role-mappings.ROLE_CREATE=dataflow.create --> All these properties map each ROLE in SCDF to a client scope included in the user info retrieved by the SSO server.
  • spring.cloud.dataflow.security.authorization.provider-role-mappings.RedHatSSO.role-mappings.ROLE_DEPLOY=dataflow.deploy
  • spring.cloud.dataflow.security.authorization.provider-role-mappings.RedHatSSO.role-mappings.ROLE_DESTROY=dataflow.destroy
  • spring.cloud.dataflow.security.authorization.provider-role-mappings.RedHatSSO.role-mappings.ROLE_MANAGE=dataflow.manage
  • spring.cloud.dataflow.security.authorization.provider-role-mappings.RedHatSSO.role-mappings.ROLE_MODIFY=dataflow.modify
  • spring.cloud.dataflow.security.authorization.provider-role-mappings.RedHatSSO.role-mappings.ROLE_SCHEDULE=dataflow.schedule
  • spring.cloud.dataflow.security.authorization.provider-role-mappings.RedHatSSO.role-mappings.ROLE_VIEW=dataflow.view

Finally, some considerations in the SSO side (this could vary depending on the used tool, this is for Keycloak/RedHatSSO):

  • Activate all the necessary URIs (token, userinfo, introspection...).
  • Define the 7 client scopes for the 7 SCDF roles.
  • Define a client in the SSO for SCDF where: activate the Service Accounts, define all the desired roles for the client (admin, operation, common user...), assign the 7 Client Scopes, define a mapper for the username field to avoid errors when it is null, and include the redirect uri (the real one, the hostname of the SCDF) in the list of Valid Redirect URIs (it works with a http://myhostname/*).
  • Once completed the previous point, assign each client scope to the correct Client Roles
0
On

These are all plain Spring Security OAuth settings and concepts are better documented there. We're in a process to add better docks for keycloak but in a meanwhile my old test dataflow-keycloak might get you started.

In a recent versions we added a better way to use plain jwt keys and we documented it for Azure/AD. Plan is to add similar section for keycloak.

I believe just by using issuer-uri and jwk-set-uri should give you a working setup(you still need to figure out scope to roles mappings) as Spring Security is using those to autoconfigure oauth settings. All the other settings are kinda legacy dating back times when we weren't fully on Spring Security 5.3 line.

For RH SSO I'm not sure if you're talking about some global shared instance or your private setup.