Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
mehmetemin
Advisor
Advisor

The REST Client enables you to execute HTTP requests and inspect the response directly in Visual Studio Code[1]. It's an incredibly convenient tool, particularly if you dislike stepping away from your development environment, which is a sentiment I definitely share.

I frequently use this extension to inspect aspects of my CAP application, both locally and in the cloud and I think it is immensely useful.

For local testing, I employ the mock security option from CAP allowing me to utilize Basic Authentication. When testing developments in BTP, we're able to generate instance-secret type credentials providing us with a clientid and clientsecret. However, for staging testing, which more closely imitates a production environment, we must use x509 type credentials to acquire a certificate. I will cover all three methods, but it was the certificate-based credentials that proved the most daunting, thus inspiring the creation of this post.

Basic Authentication

In local development, I use CAP's mock authentication. The auth section in my ".cdsrc.json" file looks like this:

"[development]": {
    "auth": {
        "passport": {
            "strategy": "mock",
            "users": {
                "admin": {
                    "password": "123",
                    "id": "admin",
                    "roles": ["admin", "authenticated-user"]
                },
                "authenticated user": {
                    "password": "123",
                    "id": "user",
                    "roles": ["authenticated-user"]
                },
                "anonymous user": {
                    "password": "123",
                    "id": "anonymous-user",
                    "roles": ["anonymous"]
                },
                "user of tenant t1": {
                    "password": "123",
                    "id": "u1",
                    "roles": ["authenticated-user"],
                    "tenant": "t1"
                }
            }
        }
    }
}

With different users and roles, I can test my backend for different roles. This works with a simple Basic Authentication. Let's assume that I want to retrieve the top 10 of someEntity provided by the admin service. I would compose the following request in the local-requests.http script:

### admin service working with user with admin role
GET http://localhost:4004/admin/someEntity?$count=true&$top=10 HTTP/1.1
Content-Type: application/json
Authorization: Basic admin:123

Afterwards, all you have to do is click the Send Request button, which should appear if you have successfully installed the REST Client extension. Using this script, we were able to test not only the expected results of the someEntity query, but also verify whether we correctly configured our CAP for authentication and authorization.

Development Space Testing

To acquire the necessary information, navigate to the Service Bindings of your deployed application, select the xsuaa service, and click on Show sensitive data. You'll need the clientid, clientsecret, and url properties from the xsuaa binding data. Following this, our dev-requests.http file where we have our request to get top 10 of someEntity served in admin service will look like this:

### Put the client id and secret to a variable in order to be able to reuse it throughout the file
@clientId = <client id copied from my applications xsuaa binding>
@clientSecret = <client secret copied from my applications xsuaa binding>
### Get JWT token
# @name getCredentials
POST <the authentication url from my applications xsuaa binding followed by "/oauth/token?grant_type=client_credentials">
Authorization: Basic {{clientId}} {{clientSecret}}

@token =  {{getCredentials.response.body.access_token}}

### Get top 10 entities served in admin service
GET <url of your backend>/admin/someEntity?$count=true&$top=10 HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{token}}

We need to issue first the POST request to get the JWT token, which will be then automatically stored in the variable token. Afterwards, we use this token in our GET requst as you can see in the script, in the Authorization header.

Testing in the Staging Space

For this stage, we need to get the token using x509 type credentials. Rishabh has written a very nice bash script in a very nice blog post and I have enhanced it a little to get the environment variables automatically. So our extract-certificate.sh script looks like this:

#!/bin/bash

if [ $# -eq 0 ]; then
  echo "Usage: get_environment_variables.sh <app_name>"
  exit 1
fi

APP_NAME=$1
ENV_VARS=$(cf env $APP_NAME)

# Extract VCAP_SERVICES
START_LINE=$(echo "$ENV_VARS" | grep -n "VCAP_SERVICES:" | cut -d ':' -f 1)
END_LINE=$(echo "$ENV_VARS" | grep -n "VCAP_APPLICATION:" | cut -d ':' -f 1)
END_LINE=$(($END_LINE-1))

VCAP_SERVICES=$(echo "$ENV_VARS" | sed -n "$START_LINE,$END_LINE p")
VCAP_SERVICES=${VCAP_SERVICES#"VCAP_SERVICES: "}


echo "$VCAP_SERVICES" > VCAP_SERVICES.json

# determine if client credentials or certificate
certificate=$(echo "$VCAP_SERVICES" | jq -r '.xsuaa[0].credentials.certificate')

# Check if "certificate" exists
if [ -n "$certificate" ] && [ "$certificate" != "null" ]; then
    echo "Certificate exists. Preparing the files."

    echo "$VCAP_SERVICES" | jq --raw-output '.xsuaa[0].credentials.key' > key.pem
    echo "$VCAP_SERVICES" | jq --raw-output '.xsuaa[0].credentials.certificate' > cert.pem

    KEY=`cat key.pem`
    CERT=`cat cert.pem`
    URL=`echo "$VCAP_SERVICES" | jq --raw-output '.xsuaa[0].credentials.certurl'`
    CLIENTID=`echo "$VCAP_SERVICES" | jq --raw-output '.xsuaa[0].credentials.clientid'`

    if [ "$KEY" = "null" ] || [ "$CERT" = "null" ] || [ "$URL" = "null" ] || [ "$CLIENTID" = "null" ]; then
      ENV_VARS_FILENAME = "env_var.json"
      echo "Missing property. 'key', 'certificate', 'clientid' and 'certurl' have to be present in the environment variables. Check the file 'env_var.json'"
      echo "$VCAP_SERVICES" > env_var.json
      exit 1
    fi

else
    echo "Certificate does not exist."
fi

After logging into your BTP account via cf cli, run the script with your backend's name: extract-certificate.sh <name-of-your-backend>. This will generate the necessary cert.pem and key.pem files. Once we have these files, we can set up the REST Client extension. Open VSCode's settings and search for @ext:humao.rest-client Certificates, then choose Edit in settings.json. This will open the settings in JSON format and we need to place the following piece to this settings file:

"rest-client.certificates": {
    "<the cert url from my applications xsuaa binding without the protocol>": {
      "cert": "./path/to/your/file/relative/to/workspace/cert.pem",
      "key": "./path/to/your/file/relative/to/workspace/key.pem"
    }
  },

This configuration allows us to obtain the JWT token. So in our staging-requests.http file we can issue a JWT token to use it to test our backend:

### Issue JWT Token
# @name issueJWTToken
POST <the cert url from my applications xsuaa binding followed by "/oauth/token">
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=<client id copied from my applications xsuaa binding. It is important that this has to be URL encoded, e.g., instead of '!' we should have '%21' etc.>

###
@token =  {{issueJWTToken.response.body.access_token}}

### Get top 10 entities served in admin service
GET <url of your backend>/admin/someEntity?$count=true&$top=10 HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{token}}

That should suffice. After issuing the POST request, you should receive a JWT token. Like we did in the former section, we use the token in our GET requst as you can see in the script, in the Authorization header.

One shortcoming, one wish

Even though the extension documentation indicates that one can provide a path relative to the http file, I was unable to get this to function. I have submitted an issue in the extension's repository. If you're able to resolve it, any assistance provided would be appreciated, either in the issue thread or here. If you're not sure, feel free to upvote the issue to raise its visibility. The ability to provide the file paths relative to our http file would greatly streamline our work across different landscapes.

Resources:

1 Comment