SAP CAP get CF Role collections of user - node.js

I'm trying to fetch the role collections assigned to my user in CAP (NodeJS). I've assigned my user to one role collections, but it does not get reflected upon testing (BAS). I've attached my configuration and statement I use to fetch the role collections. Any clues what I'm missing?
xs-security.json
{
"xsappname": "test-cap",
"tenant-mode": "dedicated",
"description": "Security profile of called application",
"scopes": [
{
"name": "uaa.user",
"description": "UAA"
},
{
"name": "$XSAPPNAME.Admin",
"description": "Admin"
}
],
"role-templates": [
{
"name": "Token_Exchange",
"description": "UAA",
"scope-references": [
"uaa.user"
]
},
{
"name": "Admin",
"description": "Admin Role",
"scope-references": [
"$XSAPPNAME.Admin"
]
}
],
"role-collections": [
{
"name": "Admin",
"description": "Admin",
"role-template-references": [
"$XSAPPNAME.Admin"
]
}
],
"oauth2-configuration": {
"redirect-uris": [
"https://*.applicationstudio.cloud.sap/**"
]
}}
package.json
"cds": {
"build": {
"target": "."
},
"requires": {
"uaa": {
"kind": "xsuaa"
},
"db": {
"kind": "hana"
}
},
"hana": {
"deploy-format": "hdbtable"
}}
mta.yaml
Output of console.log(req.user)
{
"id": "matthijs#dummy.com",
"_roles": {
"any": 1,
"identified-user": 1,
"authenticated-user": 1
},
"attr": {},
"tenant": null}

As far as I know the roles are stored in the JWT token, not in the CDS user object itself. The user object itself only "stores" the pseudo-roles (see here: https://cap.cloud.sap/docs/guides/authorization#roles)
However you can check for specific roles using the req.user.is(<rolename>) method. (see: https://cap.cloud.sap/docs/node.js/authentication#enforcement)

Related

Azure Devops Create Pipeline (Classic way) REST API

I am migrating an Azure devops organization to another organization,
I ran into a problem where i can not create a pipeline which created in the classic way (NOT A YAML).
This is the JSON
{
"name": "PP_NAME",
"folder": "",
"configuration": {
"designerJson": {
"options": [
{
"enabled": false,
"definition": {
"id": "DEF_ID"
},
"inputs": {
"branchFilters": "[\"+refs/heads/*\"]",
"additionalFields": "{}"
}
},
{
"enabled": false,
"definition": {
"id": "DEF_ID"
},
"inputs": {
"workItemType": "Task",
"assignToRequestor": "true",
"additionalFields": "{}"
}
}
],
"variables": {
"system.debug": {
"value": "false",
"allowOverride": true
}
},
"tags": [],
"process": {
"phases": [
{
"name": "Agent job 1",
"refName": "Job_1",
"condition": "succeeded()",
"target": {
"executionOptions": {
"type": 0
},
"allowScriptsAuthAccessOption": false,
"type": 1
},
"jobAuthorizationScope": "project"
}
],
"target": {
"agentSpecification": {
"identifier": "windows-2019"
}
},
"type": 1
},
"quality": "definition",
"path": "\\",
"repository": {
"id": "REPOSITORY_ID",
"name": "test 1",
"type": "TfsGit"
}
},
"path": "\\",
"type": "designerJson"
}
}
The output :
{
"$id": "1",
"innerException": null,
"message": "This API does not support creating pipelines of configuration type DesignerJson.",
"typeName": "Microsoft.Azure.Pipelines.WebApi.UnsupportedConfigurationTypeException, Microsoft.Azure.Pipelines.WebApi",
"typeKey": "UnsupportedConfigurationTypeException",
"errorCode": 0,
"eventId": 3000
}
According the the AZDO documentation, it is possible to create a pipeline with the classic way.
Thanks !
To create a classic pipeline, you can use this REST API Definitions - Create.
If you are not sure about the request body, you can use REST API Definitions - Get to get the definition of a classic pipeline as a reference.

Gitlab: Dependency scanner report is not shown on security dashboard

I am trying to create my own security scanner which will check dependencies. To test the functionality, I created a "mock scanner" which downloads a file from webhook, and saves it as an artifact ought to be uploaded to the server.
The artifact is uploaded successfully and in the CI output I can see the 201 code, but for some reason it is not presented in the security dashboard.
What am I doing wrong?
Thank you!
The CI job looks as following:
mysec_dependency_scanning:
stage: test
script:
- curl https://webhook.site/XXXX -o gl-dependency-scanning-report.json
- sleep 3
allow_failure: true
artifacts:
reports:
dependency_scanning: gl-dependency-scanning-report.json
The content of the json file is from the example provided by gitlab and it as following:
{
"version": "2.0",
"vulnerabilities": [
{
"id": "51e83874-0ff6-4677-a4c5-249060554eae",
"category": "dependency_scanning",
"name": "alik alik",
"message": "Regular Expression Denial of Service in debug",
"description": "alik to regular expression denial of service when untrusted user input is passed into the `o` formatter. It takes around 50k characters to block for 2 seconds making this a low severity issue.",
"severity": "Unknown",
"solution": "Upgrade to latest versions.",
"scanner": {
"id": "dadada",
"name": "dadada"
},
"location": {
"file": "yarn.lock",
"dependency": {
"package": {
"name": "debug"
},
"version": "1.0.5"
}
},
"identifiers": [
{
"type": "gemnasium",
"name": "Gemnasium-37283ed4-0380-40d7-ada7-2d994afcc62a",
"value": "37283ed4-0380-40d7-ada7-2d994afcc62a",
"url": "https://deps.sec.gitlab.com/packages/npm/debug/versions/1.0.5/advisories"
}
],
"links": [
{
"url": "https://nodesecurity.io/advisories/534"
},
{
"url": "https://github.com/visionmedia/debug/issues/501"
},
{
"url": "https://github.com/visionmedia/debug/pull/504"
}
]
},
{
"id": "5d681b13-e8fa-4668-957e-8d88f932ddc7",
"category": "dependency_scanning",
"name": "Authentication bypass via incorrect DOM traversal and canonicalization",
"message": "Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js",
"description": "Some XML DOM traversal and canonicalization APIs may be inconsistent in handling of comments within XML nodes. Incorrect use of these APIs by some SAML libraries results in incorrect parsing of the inner text of XML nodes such that any inner text after the comment is lost prior to cryptographically signing the SAML message. Text after the comment, therefore, has no impact on the signature on the SAML message.\r\n\r\nA remote attacker can modify SAML content for a SAML service provider without invalidating the cryptographic signature, which may allow attackers to bypass primary authentication for the affected SAML service provider.",
"severity": "Unknown",
"solution": "Upgrade to fixed version.\r\n",
"scanner": {
"id": "dadada",
"name": "dadada"
},
"location": {
"file": "yarn.lock",
"dependency": {
"package": {
"name": "saml2-js"
},
"version": "1.5.0"
}
},
"identifiers": [
{
"type": "gemnasium",
"name": "Gemnasium-9952e574-7b5b-46fa-a270-aeb694198a98",
"value": "9952e574-7b5b-46fa-a270-aeb694198a98",
"url": "https://deps.sec.gitlab.com/packages/npm/saml2-js/versions/1.5.0/advisories"
},
{
"type": "cve",
"name": "CVE-2017-11429",
"value": "CVE-2017-11429",
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-11429"
}
],
"links": [
{
"url": "https://github.com/Clever/saml2/commit/3546cb61fd541f219abda364c5b919633609ef3d#diff-af730f9f738de1c9ad87596df3f6de84R279"
},
{
"url": "https://github.com/Clever/saml2/issues/127"
},
{
"url": "https://www.kb.cert.org/vuls/id/475445"
}
]
}
],
"remediations": [
{
"fixes": [
{
"id": "5d681b13-e8fa-4668-957e-8d88f932ddc7",
}
],
"summary": "Upgrade saml2-js",
"diff": "ZGlmZiAtLWdpdCBhL...OR0d1ZUc2THh3UT09Cg==" // some content is omitted for brevity
}
]
}
I was able to fix the problem, the issue was an invalid json format.
Had to do alot of trial and error but I was able to create a working template for a dependency scanning report.
{
"version": "3.0.0",
"vulnerabilities": [
{
"id": "dfa1f7f3d56db6e1c3451a232de42f153e0335611de6f0344443d84e448ee2cf",
"category": "dddda",
"name": "dddda",
"message": "ddda",
"description": "dddda lack of validation in `index.js`.",
"cve": "dada",
"severity": "Critical",
"solution": "Upgrade to version 2.0.5 or above.",
"scanner": {
"id": "lalal",
"name": "Code_Analyzer"
},
"location": {
"file": "yarn.lock",
"dependency": {
"iid": 447,
"package": {
"name": "copy-props"
},
"version": "2.0.4"
}
},
"identifiers": [
{
"type": "dada",
"name": "dada-e9e12690-2e4d-4251-bef0-7357ddc05881",
"value": "e9e57890-5e4d-4832-bef2-7337ddc05889",
"url": "https://gitlab.com/gitlab-org/security-products/gemnasium-db/-/blob/master/npm/copy-props/CVE-2219-28503.yml"
},
{
"type": "cve",
"name": "CVE-2237-28503",
"value": "CVE-2237-28503",
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2237-28503"
}
],
"links": [
{
"url": "https://nvd.nist.gov/vuln/detail/CVE-2237-28503"
}
]
}
],
"remediations": [],
"dependency_files": [
{
"path": "yarn.lock",
"package_manager": "yarn",
"dependencies": [
{
"iid": 447,
"dependency_path": [
{
"iid": 708
},
{
"iid": 707
}
],
"package": {
"name": "copy-props"
},
"version": "2.0.4"
}
]
}
],
"scan": {
"scanner": {
"id": "lalal",
"name": "Code_Analyzer",
"url": "https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium",
"vendor": {
"name": "lalal"
},
"version": "2.29.5"
},
"type": "dependency_scanning",
"start_time": "2021-05-03T06:47:29",
"end_time": "2021-05-03T06:47:30",
"status": "success"
}
}

Getting access denied after keycloak login. I dont have any roles in my keycloak server

I am implementing Keycloak authorization to my Node.js application. I created a realm and a client inside of it. I don't have any roles either in realm or in client. I have a route "/test" which is protected with Keycloak.
My keycloak.json looks like this:
{
"realm": "demo",
"auth-server-url": "http://localhost:8080/auth",
"ssl-required": "external",
"resource": "myapp",
"public-client": true,
"confidential-port": 0
}
Define roles (realm roles or client roles), assign the roles to your user (user which you use to perform the test), check your role scope mappings (or you can configure your client as full-scope for testing purpouse), and check that you are protecting your '/test' route with those same permissions.
E.g. you can try with keycloak-nodejs adapter (example).
Look at this configuration file (keycloak realm configuration example):
{
"realm": "nodejs-example",
"enabled": true,
"sslRequired": "external",
"registrationAllowed": true,
"privateKey": "...................",
"publicKey": ".....................",
"requiredCredentials": [ "password" ],
"users" : [
{
"username" : "user",
"enabled": true,
"email" : "sample-user#nodejs-example",
"firstName": "Sample",
"lastName": "User",
"credentials" : [
{ "type" : "password",
"value" : "password" }
],
"realmRoles": [ "user" ],
"clientRoles": {
"account": ["view-profile", "manage-account"]
}
}
],
"roles" : {
"realm" : [
{
"name": "user",
"description": "User privileges"
},
{
"name": "admin",
"description": "Administrator privileges"
}
]
},
"scopeMappings": [
{
"client": "nodejs-connect",
"roles": ["user"]
}
],
"clients": [
{
"clientId": "nodejs-connect",
"enabled": true,
"publicClient": true,
"baseUrl": "/",
"adminUrl" : "http://localhost:3000/",
"baseUrl" : "http://localhost:3000/",
"redirectUris": [
"http://localhost:3000/*"
],
"webOrigins": []
},
{
"clientId": "nodejs-apiserver",
"enabled": true,
"secret": "secret",
"redirectUris": [
"http://localhost:3000/*"
],
"webOrigins": [
"http://localhost:3000/*"
],
"serviceAccountsEnabled": true,
"authorizationServicesEnabled": true,
"authorizationSettings": {
"resources": [
{
"name": "resource",
"type": "urn:nodejs-apiserver:resources:default",
"ownerManagedAccess": false,
"uris": [
"/*"
],
"scopes": [
{
"name": "view"
},
{
"name": "write"
}
]
}
],
"policies": [
{
"name": "Default Policy",
"description": "A policy that grants access only for users within this realm",
"type": "js",
"config": {
"code": "// by default, grants any permission associated with this policy\n$evaluation.grant();\n"
}
},
{
"name": "Default Permission",
"description": "A permission that applies to the default resource type",
"type": "resource",
"config": {
"defaultResourceType": "urn:nodejs-apiserver:resources:default",
"applyPolicies": "[\"Default Policy\"]"
}
}
]
}
}
]
}
Explanation:
From this sample, look at how a user has roles assigned (realm roles: "user", account client roles: "account": ["view-profile", "manage-account"]):
{
...
"users" : [
{
"username" : "user",
"enabled": true,
"email" : "sample-user#nodejs-example",
"firstName": "Sample",
"lastName": "User",
"credentials" : [
{ "type" : "password",
"value" : "password" }
],
"realmRoles": [ "user" ],
"clientRoles": {
"account": ["view-profile", "manage-account"]
}
}
],
...
}
Look at how realm Roles are defined:
{
...
"roles" : {
"realm" : [
{
"name": "user",
"description": "User privileges"
},
{
"name": "admin",
"description": "Administrator privileges"
}
]
},
...
}
Look at how this sample uses a 'scope mapping' to map roles from realm to a user authenticated by a client (read more about this here role scope mapping):
{
...
"scopeMappings": [
{
"client": "nodejs-connect",
"roles": ["user"]
}
],
...
}
Look at how clients are defined. Check that 'nodejs-connect' client is public and 'nodejs-apiserver' is secret. In this sample, server is using the 'Authorization Api' to protect resources but you could protect your resources by granted roles only (if you want).
{
...
"clients": [
{
"clientId": "nodejs-connect",
"enabled": true,
"publicClient": true,
"baseUrl": "/",
"adminUrl" : "http://localhost:3000/",
"baseUrl" : "http://localhost:3000/",
"redirectUris": [
"http://localhost:3000/*"
],
"webOrigins": []
},
{
"clientId": "nodejs-apiserver",
"enabled": true,
"secret": "secret",
"redirectUris": [
"http://localhost:3000/*"
],
"webOrigins": [
"http://localhost:3000/*"
],
"serviceAccountsEnabled": true,
"authorizationServicesEnabled": true,
"authorizationSettings": {
"resources": [
{
"name": "resource",
"type": "urn:nodejs-apiserver:resources:default",
"ownerManagedAccess": false,
"uris": [
"/*"
],
"scopes": [
{
"name": "view"
},
{
"name": "write"
}
]
}
],
"policies": [
{
"name": "Default Policy",
"description": "A policy that grants access only for users within this realm",
"type": "js",
"config": {
"code": "// by default, grants any permission associated with this policy\n$evaluation.grant();\n"
}
},
{
"name": "Default Permission",
"description": "A permission that applies to the default resource type",
"type": "resource",
"config": {
"defaultResourceType": "urn:nodejs-apiserver:resources:default",
"applyPolicies": "[\"Default Policy\"]"
}
}
]
}
}
]
...
}
Finally, look at javascript (index.js) file to see how it uses 'keycloak-connect' (adapter) to protect and enforce access policies (usage of Authorization Api).
Tip
In development, you can get an access token and use this page to decode and see the token's content.
JWT.IO
I hope this helps.
I also had a 403 - Access Denied. What helped was stepping through the auth code of keycloak-connect. The token validation happens in the function validateToken in node_modules\keycloak-connect\middleware\auth-utils\grant-manager.js
if (!token) {
reject(new Error('invalid token (missing)'))
} else if (token.isExpired()) {
reject(new Error('invalid token (expired)'))
} else if (!token.signed) {
reject(new Error('invalid token (not signed)'))
} else if (token.content.typ !== expectedType) {
reject(new Error('invalid token (wrong type)'))
} else if (token.content.iat < this.notBefore) {
reject(new Error('invalid token (stale token)'))
} else if (token.content.iss !== this.realmUrl) {
reject(new Error('invalid token (wrong ISS)'))
}
...
For me, the problem was that I configured the url to the keycloak server without the schema (https). token.content.iss includes the schema and so it rejected because of token.content.iss !== this.realmUrl.
Unfortunately they seem to swallow those valuable Error messages without logging or returning them. I opened a question regarding this behavior.

Missing Subscription Key field in Swagger API connector (trough Azure API Management) in Logic App

I have created a REST API with a Swagger/OPEN API specification which I will like to consume trough a Azure API Management tenant in a Logic App.
When I download the specification it looks like this:
{
"swagger": "2.0",
"info": {
"title": "Leasing",
"version": "1.0"
},
"host": "ENDPOINT.azure-api.net",
"basePath": "/leasing",
"schemes": [
"http",
"https"
],
"securityDefinitions": {
"apiKeyHeader": {
"type": "apiKey",
"name": "Ocp-Apim-Subscription-Key",
"in": "header"
},
"apiKeyQuery": {
"type": "apiKey",
"name": "subscription-key",
"in": "query"
}
},
"security": [
{
"apiKeyHeader": []
},
{
"apiKeyQuery": []
}
],
"paths": {
"/{Brand}/groups": {
"get": {
"description": "Get a list of leasing groups on a brand",
"operationId": "GetGroups",
"parameters": [
{
"name": "Brand",
"in": "path",
"description": "Selection of possible brands",
"required": true,
"type": "string",
"enum": [
"Volkswagen",
"Audi",
"Seat",
"Skoda",
"VolkswagenErhverv",
"Porsche",
"Ducati"
]
}
],
"responses": {
"200": {
"description": "Returns a list of leasing groups",
"schema": {
"$ref": "#/definitions/GroupArray"
}
},
"400": {
"description": "If the brand is not valid",
"schema": {
"$ref": "#/definitions/Error"
}
}
},
"produces": [
"application/json"
]
}
}
},
"definitions": {
"Group": {
"type": "object",
"properties": {
"id": {
"format": "int32",
"type": "integer"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"leasingModelCount": {
"format": "int32",
"type": "integer"
},
"lowestMonthlyFee": {
"format": "int32",
"type": "integer"
}
}
},
"Error": {
"type": "object",
"properties": {
"code": {
"enum": [
"NotValidBrand",
"NotValidGroupId"
],
"type": "string",
"x-ms-enum": {
"name": "ErrorCode",
"modelAsString": true
}
},
"message": {
"type": "string"
}
}
},
"GroupArray": {
"type": "array",
"items": {
"$ref": "#/definitions/Group"
}
}
}
}
When I add this in a Logic App with the connector HTTP + Swagger I only get to define the {Brand} query input but not the various ways of using the Subscriptions key (header or query) as defined in SecurityDefiniations.
The whole securityDefinitions and security section are automatically generated in the Azure API Management service, but not recognized in Logic App.
See image of missing subscription key field:
What am I doing wrong?
Update
I have tried the following:
Usage of the 'Authentication' field (but this field is limited to certain types of auths flows https://learn.microsoft.com/en-us/azure/connectors/connectors-native-http#authentication)
Change the Logic App 'Http + Swagger'-action in code to add the header parameter, but this action converts the action to a simple 'Http' action and therfore loosing the automatic schema generation from Swagger.
I think you need to specify this in the Authentication-field in a JSON format. Something like:
{
"apiKeyHeader" : "your Ocp-Apim-Subscription-Key",
"apiKeyQuery" : "your subscription key"
}

Error creating a customContent on a confluence addon

Today I was trying to create a confluence addon for my company and I've try following atlassian documents.
My problem comes trying to run the express app when adding a new customContent to the atlassian-connect.json, after running npm start I get the following error.
Failed to register with host https‍://admin:xxx#xxx.atlassian.net/wiki (200)
{"type":"INSTALL","pingAfter":300,"status":{"done":true,"statusCode":200,"con
tentType":"application/vnd.atl.plugins.task.install.err+json","subCode":"upm.
pluginInstall.error.descriptor.not.from.marketplace","source":"https‍://1a0adc
8f.ngrok.io/atlassian-connect.json","name":"https‍://1a0adc8f.ngrok.io/atlassi
an-connect.json"},"links":{"self":"/wiki/rest/plugins/1.0/pending/b88594d3-c3
c2-4760-b687-c8d860c0a377","alternate":"/wiki/rest/plugins/1.0/tasks/b88594d3
-c3c2-4760-b687-c8d860c0a377"},"timestamp":1502272147602,"userKey":"xxx","id":"xxx"}
Add-on not registered; no compatible hosts detected
This is my atlassian-connect.json file:
{
"key": "my-add-on",
"name": "Ping Pong",
"description": "My very first add-on",
"vendor": {
"name": "Angry Nerds",
"url": "https://www.atlassian.com/angrynerds"
},
"baseUrl": "{{localBaseUrl}}",
"links": {
"self": "{{localBaseUrl}}/atlassian-connect.json",
"homepage": "{{localBaseUrl}}/atlassian-connect.json"
},
"authentication": {
"type": "jwt"
},
"lifecycle": {
"installed": "/installed"
},
"scopes": [
"READ"
],
"modules": {
"generalPages": [
{
"key": "hello-world-page-jira",
"location": "system.top.navigation.bar",
"name": {
"value": "Hello World"
},
"url": "/hello-world",
"conditions": [{
"condition": "user_is_logged_in"
}]
},
{
"key": "customersViewer",
"location": "system.header/left",
"name": {
"value": "Hello World"
},
"url": "/hello-world",
"conditions": [{
"condition": "user_is_logged_in"
}]
}
],
"customContent": [
{
"key": "customer",
"name": {
"value": "Customers"
},
"uiSupport": {
"contentViewComponent": {
"moduleKey": "customersViewer"
},
"listViewComponent": {
"moduleKey": "customerList"
},
"icons": {
"item": {
"url": "/images/customers.png"
}
}
},
"apiSupport": {
"supportedContainerTypes": ["space"]
}
}
]
}
}
Does anybody has an idea on whats going on?
The contentViewComponent can't find the generalPage it is referencing in moduleKey.
From the docs:
In the snippet above, the moduleKey “customersViewer” maps to a
generalPage module we have defined in our add-on. This generalPage is
passed the context parameters we specify, and visualizes our content
accordingly.
If you change the generalPage with the key hello-world-page-confluence to customersVieweryou be able to install and get up and running.

Resources