0

I'm using the SAP S/4HANA Cloud SDK (S4SDK) in conjunction with the Cloud Application Programming Model (CAPM). I have workflow and Fiori artifacts in Neo that consume the S4SDK service running in Cloud Foundry (CF). The S4SDK service is then calling S/4HANA (Public) Cloud using a system user. I have set up Principle Propagation from Neo to CF as per the following link:

Principal Propagation from the Neo to the Cloud Foundry Environment

I've been developing my project for a couple of months now. Now the time has come to set up role based access to my OData services. I need to ensure that I have back-end validation to check that only approvers can set the status of my request to 'Approved', for example.

I plan to do this by declaring multiple OData services in the my-service.cds file. Then using spring-security I will only give those with the approvers role-collection access to the approvers service.

I'm following this blog:

Step 7 with SAP S/4HANA Cloud SDK: Secure your Application on SAP Cloud Platform, CloudFoundry

My xs-security.json looks like this:

{
  "xsappname": "s4projectcreate",
  "tenant-mode": "dedicated",
  "description": "Security profile of called application",
  "scopes": [
    {
      "name": "uaa.user",
      "description": "UAA"
    },
    {
      "name": "$XSAPPNAME.AdminApprove",
      "description": "UAA"
    },
    {
      "name": "$XSAPPNAME.RiskApprove",
      "description": "UAA"
    }
  ],
  "role-templates": [
    {
      "name": "Token_Exchange",
      "description": "UAA",
      "scope-references": [
        "uaa.user"
      ]
    },
    {
      "name": "Admin_Approver",
      "description": "Request Admin Approver",
      "scope-references": [
        "$XSAPPNAME.AdminApprove"
      ]
    },
    {
      "name": "Risk_Approver",
      "description": "Request Risk Approver",
      "scope-references": [
        "$XSAPPNAME.RiskApprove"
      ]
    }
  ]
}

I made the following entries in my spring-security.xml (otherwise as per the blog):

<sec:intercept-url pattern="/odata/v2/ProjCreateApprover/**" access="#oauth2.hasScope('${xs.appname}.AdminApprove')" method="GET" />
<sec:intercept-url pattern="/odata/v2/**" access="isAuthenticated()" method="GET" />

When I go to the CF cockpit (org. level) and navigate to the Security/Roles section I can create a new role collection and add the two role templates to it.

I then navigate to the Trust Configuration where I see both the SCIA (a.k.a. SAP Cloud Identity) and 'Neo' sections. The latter I configured when I set up the principle propagation from Neo to CF. I can go into either account and enter my user email address. Then I can assign my role collection to the user (me).

The problem is, whatever I do here doesn't seem to enable me to pass the new security check. I always get the following message when I try to access the protected path: Access is deniedaccess_denied

How should I be assigning this role? Do I use the email address, because that is normally the ID in CF? Should I be doing something at the space or even app level? Do I need to rebind the XSUAA service or something?

I'm testing in the browser. If I don't already have a session it is getting me to log in. The unprotected service still works fine.

APPENDUM: Here is the JWT payload. It looks like I do have the scopes from the role:

{
  "jti": "aa4f13c4c456429ab7d7f**218b1ef86",
  "ext_attr": {
    "enhancer": "XSUAA",
    "zdn": "test**n"
  },
  "given_name": "P0000**",
  "xs.user.attributes": {},
  "family_name": "unknown.org",
  "sub": "123526eb-fda8-49cf-a507-506**d28efba",
  "scope": [
    "s4projectcreate!t23.AdminApprove",
    "openid",
    "s4projectcreate!t23.RiskApprove",
    "uaa.user"
  ],
  "client_id": "sb-s4projectcreate!t23",
  "cid": "sb-s4projectcreate!t23",
  "azp": "sb-s4projectcreate!t23",
  "grant_type": "urn:ietf:params:oauth:grant-type:saml2-bearer",
  "user_id": "1235**eb-fda8-49cf-a507-506b8d28efba",
  "origin": "httpsap1.hana.ondemand.comc3d8**a55",
  "user_name": "p0000**",
  "email": "P0000**@unknown.org",
  "rev_sig": "8f**7376",
  "iat": 1552347533,
  "exp": 1552390733,
  "iss": "http://test**n.localhost:8080/uaa/oauth/token",
  "zid": "382217ca-6332-4b03-85ee-8f**85fd903a",
  "aud": []
}
Sandra Rossi
  • 11,934
  • 5
  • 22
  • 48
  • With SAP Cloud Identity, the default user identifier should be email address. Can you check if your JWT contains the relevant scopes? You can achieve this by building a small service that uses the AuthTokenAccessor and returns the current token. – Sander Wozniak Mar 11 '19 at 11:59
  • Thanks, I've added the JWT payload in the question text. It looks like I do have the scopes and I was surprised that the user ID is actually the p-number, I think because it has been propagated from neo – Mike Doyle Mar 12 '19 at 01:28
  • Now I've removed the role collection from my user, but the JWT still shows the scopes. In fact the token looks the same. How do I ensure that the JWT is updated to reflect my current role assignment? – Mike Doyle Mar 12 '19 at 02:17
  • I've added the scope to the router in the router component (xs-app.json). Given that the back-end has been set up to require the JWT I'm thinking that maybe this step (spring security) might be redundant, because the router will apply the role checks. – Mike Doyle Mar 12 '19 at 09:11
  • Have added ** to sensitive fields like my user id. – Mike Doyle Mar 12 '19 at 09:11
  • 1
    Few comments to your questions: 1. In order to invalidate the JWT you need to expose a logout endpoint in the approuter which invalidates the token. I have written how to do this in this book chapter : https://s3-eu-west-1.amazonaws.com/gxmedia.galileo-press.de/leseproben/4655/reading_sample_sappress_1715_ExtendingSAPS4HANA.pdf – Philipp Herzig Mar 12 '19 at 09:50
  • 1
    2. You can add the scopes to the AppRouter to do a first level authorization check. However, in a lot of applications you will work with the authorizations in a more fine-grained manner inside the microservice. Furthermore, you should still protect your microservices as they are otherwise unprotected in the internet. This is also discussed in this book chapter: https://s3-eu-west-1.amazonaws.com/gxmedia.galileo-press.de/leseproben/4655/reading_sample_sappress_1715_ExtendingSAPS4HANA.pdf – Philipp Herzig Mar 12 '19 at 09:53
  • 1
    To investigate further: 1. As JWT contains the scope, could you check your `cf env` and ensure that the xsappname is correct? 2. Which http error code do you actually get, is it an 401 or a 403? 3. Related to (2), does it work with authentication enabled only, i.e., w/o scope check but validly authenticated user at the backend microservice? Thanks. – Philipp Herzig Mar 12 '19 at 09:56
  • Thanks so much Philipp for your help. I've run the `cf env` command and under xsuaa it shows xsappname=s4projectcreate!t23. It's always worked fine with authenticated user specified. Is the 'xs.appname' syntax in the spring-security.xml file correct? – Mike Doyle Mar 21 '19 at 10:17
  • Quick follow-up – Philipp Herzig Mar 21 '19 at 10:39
  • Quick follow-up 1) which error code do you receive on the `/odata/v2/ProjCreateApprover/` route?401, 403, or something else? 2) What is the value of your `application.properties` files typically found under under `application/src/main/resources` of your sdk project? (assuming you've started from the archetype) – Philipp Herzig Mar 21 '19 at 14:05
  • Thanks again for your help Philipp. I had to put this park this investigation for a while, but I'm back on it now. Regarding the application.properties it has the following value: xs.appname=s4projectcreate-srv. Of course this doesn't match the s4projectcreate!t23 value which comes from the service binding I believe. – Mike Doyle Aug 27 '19 at 04:10
  • I'm trying to implement a check programmatically and to assist I've written a function which returns the authorisations as a string (essentially currentUser.getAuthorizations().toString()). For one of my test users (#3) this function does return the scopes that are present in the assigned role. For another user (#2), assigned a different role, it returns an empty array. When I check the OAuth scopes using the method listed in your blog (Step 7 with SAP Cloud SDK: Secure your Application on SAP Cloud Platform, CloudFoundry) 'action=who' I see the scopes I expect for both users. – Mike Doyle Aug 27 '19 at 04:16
  • Why would the scopes appear in the OAuth readout yet not be seen using the User API? I think this might be the crux of the issues that I listed before in this question. NB I have followed your instructions and gone to [router-url]/do/logout (as listed in xs-app.json) and it seems to log me out. When I run my test function again I still don't see the scopes that I see on the 'action=who' page. – Mike Doyle Aug 27 '19 at 04:20
  • One last thing I've noticed is that when I look at the roles in the CF cockpit under application s4projectcreate-srv there is a difference between the 'Default instance' roles create for my new role and for the older roles (the ones which are working). The new roles have the edit and delete icons disabled. I created a test role manually here using the same role template and then these icons were enabled. This didn't solve my issue though – Mike Doyle Aug 27 '19 at 05:28

1 Answers1

0

go to the sap cloud platform, inside your subaccount u will get trust management just enable it . u will see your role-reference overthere , by doing this u will be authorize to access the service.

raj
  • 1
  • 3