SAP / cloud-security-services-integration-library

Integration libraries and samples for authenticating users and clients bound to XSUAA authentication and authorization service or Identity authentication service.
Apache License 2.0
151 stars 135 forks source link

Issue with XsuaaJkuValidator when application is bound to both system plan and application/broker plan #396

Closed manoj-mathivanan closed 4 years ago

manoj-mathivanan commented 4 years ago

Hi,

XsuaaJkuValidator is also registered as one of the token validator in SAPOfflineTokenServicesCloud which checks if the jku in the token matches the domain in the xsuaa binding.

For application & broker plan the uaadomain is the same and it does not match with the system plan.

During runtime, when a token is created for system plan flow, the jku in token is : "https://uaa.cf.sap.hana.ondemand.com/token_keys". This gets validated by XsuaaJkuValidator.java with "authentication.sap.hana.ondemand.com" which was initialized with xsuaa application instance and throws error.

The error is:

Issuer is not trusted because 'jku' 'https://uaa.cf.sap.hana.ondemand.com/token_keys' does not match uaa domain 'authentication.sap.hana.ondemand.com' of the identity service.

Can you help me out here.

Thanks & Regards Manoj

nenaraab commented 4 years ago

HI @manoj-mathivanan

the question, why do you leverage system plan at all? Do you deploy your application on XSA or on Cloud Foundry?

Thanks for clarification.

Best regards, Nena

manoj-mathivanan commented 4 years ago

Hi Nena,

Thanks a lot for your reply.

We use Cloud Foundry. We have a dashboard attached to the service instance with which he can view some information about the service instance and configure the service instance. This dashboard uses system plan to authenticate the user.

Thanks & Regards Manoj

nenaraab commented 4 years ago

Hi @manoj-mathivanan

how have you done it previously? Is it a feature request? I'm not aware of such a use case...

Have you tried to setup a validation only for that dashboard-with-system-plan case as it is described here: https://github.com/SAP/cloud-security-xsuaa-integration/blob/master/java-security/README.md#basic-usage

Instead of "Setup Step 1: Load the Service Configuration(s)" you can setup the config for Xsuaa Service of plan "system" by your own:

OAuth2ServiceConfiguration systemConfig = CFEnvironment.loadForServicePlan(Service.XSUAA, Plan.SYSTEM)

System plan has a lot of disadvantages, see SAP-internal references:

manoj-mathivanan commented 4 years ago

Hi Nena,

Thanks a lot for your suggestions.

This is not a new feature request from our side, using System plan, application. broker in the same app was being done for a long time. Our product - Enterprise Messaging which was released more than a year back has been using it. So we have a release version available. Due to the disadvantages you have mentioned, we have discontinued System plan for new customers for the last few months. But we still support this feature for the existing customers. This is the reason for still supporting all the plans.

The problem poped when we started migrating to the new security libraries. In the old set up I guess we did not have jku validation in the library and everything was working fine.

We are exactly using the code what you have suggested. The link to the file change is below: https://github.wdf.sap.corp/enterprise-messaging/xbem-hub/blob/354f84e0f0f141a66d54561d02d765578c34ccc2/ehub-app/src/main/java/com/sap/xbem/ehub/app/config/security/WebSecurityConfig.java#L113

Thanks & Regards Manoj

nenaraab commented 4 years ago

Hi @manoj-mathivanan,

I guess your current solution is not working, right?

Because SAPOfflineTokenServicesCloud does not (yet) support xsuaa services that differentiate in their uaa domain and this was not what I've suggested above. My suggestion above was to setup another validator only for the system plan and to validate these kind of tokens separately, e.g. as part of the endpoint and not as part of this configuration...

Would that be a feasible intermediate solution?

Otherwise we have to enhance XsuaaJkuValidator that it supports different domains. Which is only necessary for this special case, which is not recommended at all...

Best regards, Nena

manoj-mathivanan commented 4 years ago

Hi Nena,

Getting the OAuth2ServiceConfiguration for system plan manually and building the JwtValidatorBuilder throws the error: XsuaaJkuValidator requires uaaDomain.

The exact code which was done is:

OAuth2ServiceConfiguration xsuaaSystemConfig = CFEnvironment.getInstance().loadForServicePlan(Service.XSUAA, Plan.SYSTEM);
CombiningValidator<Token> validators = JwtValidatorBuilder.getInstance(xsuaaSystemConfig).build();

When the build() method is called, it creates an XsuaaJkuValidator which throws the error XsuaaJkuValidator requires uaaDomain.

To overcome this, I tried out the below approach.

OAuth2ServiceConfiguration xsuaaSystemConfig = CFEnvironment.getInstance().loadForServicePlan(Service.XSUAA, Plan.SYSTEM);

OAuth2ServiceConfiguration serviceConfig = OAuth2ServiceConfiguration serviceConfig = OAuth2ServiceConfigurationBuilder
                .fromConfiguration(xsuaaSystemConfig)
                .withProperty(CFConstants.XSUAA.UAA_DOMAIN, "uaa.cf.sap.hana.ondemand.com")
                .build();

validators = JwtValidatorBuilder.getInstance(serviceConfig).build();

Does this approach look good? If it looks good, to build the serviceConfig I found two ways as shown below. It would be great if you can suggest one.

OAuth2ServiceConfiguration serviceConfig = OAuth2ServiceConfiguration serviceConfig = OAuth2ServiceConfigurationBuilder
                .fromConfiguration(xsuaaSystemConfig)
                .withProperty(CFConstants.XSUAA.UAA_DOMAIN, "uaa.cf.sap.hana.ondemand.com")
                .build();

or

OAuth2ServiceConfiguration serviceConfig = OAuth2ServiceConfigurationBuilder
                .fromConfiguration(xsuaaSystemConfig)
                .runInLegacyMode(true)
                .build();

Overall, I created a Filter for the URLs which uses system plan and I cached the token manually using: SecurityContext.setToken(token); and removed the pattern from spring "authenticated" part. Hope this is what you meant.

Thanks & Regards Manoj

nenaraab commented 4 years ago

Hi @manoj-mathivanan

can you pls share with me, the uaa domain of VCAP_SERVICES for plan system?

Best regards, Nena

manoj-mathivanan commented 4 years ago

Hi Nena,

The xsuaa environment looks like:

{
    "binding_name": null,
    "credentials": {
     "apiurl": "https://api.authentication.sap.hana.ondemand.com",
     "clientid": "sb-xbem-ui-xbem-perf-tests!s298",
     "clientsecret": "qEY7_bASOHSrXstkCKlBvvSMV7k",
     "identityzone": "uaa",
     "identityzoneid": "uaa",
     "sburl": "https://internal-xsuaa.authentication.sap.hana.ondemand.com",
     "tenantid": "e55b04c5-e75a-4357-92e1-af7d54e405c9",
     "tenantmode": "dedicated",
     "url": "https://uaa.cf.sap.hana.ondemand.com",
     "verificationkey": "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArnSd/Sxq+AqXqtc6fYYcyvgvrN2g+dd643AsTYjLZJxVBBdxADyhW/R408tRyrcZzlkC1pAbyxD3cc5tglmHEiAl6dWd8rCVQeWeQMma+vDR2WkpqmhUGqdy13Y/esezrqhvc2RNCCtrtCFf3i3JRzh9hS7pnWlqzzyRaVETOcpS9Q5jeyytZrxXjZAYX77QCDgQdpELNhL/iz0GzvalGT2h4Jdb3i7y7Co/9cfm3jAuS8N1qbqsR/o6rzzeIrjDCuI5/BLL3Bph76TvgdHTe/tN+iRNG5xlg0460GyjSwQqp1mR21+sVFmTE2Flc2fAI2473B93Xk6IEoEI96eqYwIDAQAB-----END PUBLIC KEY-----",
     "xsappname": "xbem-ui-xbem-perf-tests!s298"
    },
    "instance_name": "xbem-xsuaa-system",
    "label": "xsuaa",
    "name": "xbem-xsuaa-system",
    "plan": "system",
    "provider": null,
    "syslog_drain_url": null,
    "tags": [
     "xsuaa"
    ],
    "volume_mounts": []
   }

It doesnot have a uaa domain. Thats the problem.

Regards Manoj

nenaraab commented 4 years ago

Ok. Then you could implement it so:

OAuth2ServiceConfiguration serviceConfig = OAuth2ServiceConfigurationBuilder
                .fromConfiguration(xsuaaSystemConfig)
                .withProperty(CFConstants.XSUAA.UAA_DOMAIN, xsuaaSystemConfig.getUrl().getHost())
                .build();

The rest should fit!

Best regards, Nena

manoj-mathivanan commented 4 years ago

Hi Nena,

Thanks a lot for helping out.

Regards Manoj