google-cloud-storage CORS Setting - google-cloud-storage

I've done the CORS set to bucket of google cloud storage, there is no Access-Control-Allow-Origin header
If my settings are wrong , I want you to tell me the right way .
My Settings
$ cat cors-json-file.json
[
{
"origin": [
"*"
],
"responseHeader": ["Origin", "Accept", "X-Requested-With", "Authorization", "Content-Type", "Content-Length", "Accept-Encoding", "X-CSRF-Token"],
"method": [
"GET",
"OPTIONS"
],
"maxAgeSeconds": 1
}
]
$ gsutil cors set cors-json-file.json gs://stone-swallow
$ gsutil cors get gs://stone-swallow
[{"origin": ["*"], "responseHeader": ["Origin", "Accept", "X-Requested-With", "Authorization", "Content-Type", "Content-Length", "Accept-Encoding", "X-CSRF-Token"], "method": ["GET", "OPTIONS"], "maxAgeSeconds": 1}]
try browser error message
var invocation = new XMLHttpRequest();
var url = 'http://storage.googleapis.com/stone-swallow/arcanine.png';
function callOtherDomain() {
if(invocation) {
invocation.open('GET', url, true);
invocation.send();
}
}
callOtherDomain();
XMLHttpRequest cannot load http://storage.googleapis.com/stone-swallow/arcanine.png. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.

I had the same problem, and the solution was to add a Header Origin: "https://ourapp.appspot.com" to the initial resumable request.
However, some librares, for example sun.net.www.protocol.http.HttpURLConnection doesn't allow you to change the Origin header because of the following variable :
restrictedHeaders = new String[]{"Access-Control-Request-Headers", "Access-Control-Request-Method", "Connection", "Content-Length", "Content-Transfer-Encoding", "Host", "Keep-Alive", "Origin", "Trailer", "Transfer-Encoding", "Upgrade", "Via"};
My workaround was to create a new HttpRequest with a library that allows to update the Origin header. I used Okhttp in my case (as former Android developper).
OkHttpClient client = new OkHttpClient();
AppIdentityService appIdentityService = credential.getAppIdentityService();
Collection<String> scopes = credential.getScopes();
String accessToken = appIdentityService.getAccessToken(scopes).getAccessToken();
Request request = new Request.Builder()
.url("https://www.googleapis.com/upload/storage/v1/b/" + bucket + "/o?name=" + fileName + "&uploadType=resumable")
.post(RequestBody.create(MediaType.parse(mimeType), new byte[0]))
.addHeader("X-Upload-Content-Type", mimeType)
.addHeader("X-Upload-Content-Length", "" + length)
.addHeader("Origin", "http://localhost:8080")
.addHeader("Origin", "*")
.addHeader("authorization", "Bearer "+accessToken)
.build();
Response response = client.newCall(request).execute();
return response.header("location");

Make sure that there is public-read on the bucket:
$ gsutil -m acl set -R -a public-read gs://stone-swallow

I had a very similar problem, took me few hours to realize I must set responseHeader to `["*"] in my CORS config json.

Specify an ‘Origin’ header on your GET method. This should fix the issue.

Related

'Access-Control-Allow-Origin' header value not equal to the supplied origin, POST method

I get the following message in the Chrome dev tools console when submitting a contact form (making a POST request) on the /about.html section my portfolio web site:
Access to XMLHttpRequest at 'https://123abc.execute-api.us-east-1.amazonaws.com/prod/contact' from origin 'https://example.net' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header has a value 'https://example.net/' that is not equal to the supplied origin.
I don't know how to troubleshoot this properly, any help is appreciated.Essentially, this is happening (https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSAllowOriginNotMatchingOrigin) and I don't know where within my AWS assets to fix it. This person had same problem, but i'm unsure of how to apply their fix (CORS header 'Access-Control-Allow-Origin' does not match... but it does‼)
Here is a description of the AWS stack:
Context, I am using an S3 bucket as static website using CloudFront and Route 53, this stuff works fine, has for years. When I added the form, I did the following to allow the HTTP POST request:
Cloudfront, On the site's distribution I added a behavior with all settings default except:
Path pattern: /contact (I am using this bc this is the API Gateway resource path ending)
Origin and origin groups: S3-Website-example.net.s3-website... (Selected correct origin)
Viewer protocol policy: HTTP and HTTPS
Allowed HTTP methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE
Cache HTTP methods GET and HEAD methods are cached by default: Checked OPTIONS box
Origin request policy - optional: CORS-S3Origin
Response headers policy - optional: CORS-With-Preflight
API Gateway, Created a REST API with all default settings except:
Created a resource: /contact
Created a method: POST
For /contact, Resource Actions > Enable CORS:
Methods: OPTIONS and POST both checked
Access-Control-Allow-Origin: 'https://example.net' (no ending slash)
Clicked "Enable CORS and Replace existing headers"
Results are all checked green:
✔ Add Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin Method Response Headers to OPTIONS method
✔ Add Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin Integration Response Header Mappings to OPTIONS method
✔ Add Access-Control-Allow-Origin Method Response Header to POST method
✔ Add Access-Control-Allow-Origin Integration Response Header Mapping to POST method
Created a stage called "prod", ensured it had the /contact resource, and deployed.
At the /contact - POST - Method Execution, The test works as expected (triggers Lambda func that uses SES to send email, which I do actually receive).
The only thing I feel unsure about with API Gateway is after I enable the CORS, I can't seem to find a place where that setting has been saved, and if I click again on enable CORS, it is back to the default form ( with Access-Control-Allow-Origin: '')*
Amazon SES, set up 2 verified identities for sending/receiving emails via lamda.
Lamda, set up a basic javascript function with default settings, the REST API is listed as a trigger, and does actually work as previously mentioned. The function code is:
var AWS = require('aws-sdk');
var ses = new AWS.SES({ region: "us-east-1" });
var RECEIVER = 'myemail#email.com';
var SENDER = 'me#example.net';
var response = {
"statusCode": 200,
"headers": {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
},
"isBase64Encoded": false,
"body": "{ \"result\": \"Success\"\n}"
}
exports.handler = async function (event, context) {
console.log('Received event:', event);
var params = {
Destination: {
ToAddresses: [
RECEIVER
]
},
Message: {
Body: {
Text: {
Data: 'first name: ' + event.fname + 'last name: ' + event.lname + '\nemail: ' + event.email + '\nmessage: ' + event.message,
Charset: 'UTF-8'
}
},
Subject: {
Data: 'Website Query Form: ' + event.name,
Charset: 'UTF-8'
}
},
Source: SENDER
};
return ses.sendEmail(params).promise();
};
The only thing i can think of here is to maybe update the response to have "headers": {"Access-Control-Allow-Origin": "https://example.net"}
S3 bucket that holds the site contents, in permissions > CORS, I have the following JSON to allow a post of the contact form (notice no slash):
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"POST"
],
"AllowedOrigins": [
"https://example.net"
],
"ExposeHeaders": []
}
]
Permissions/Roles, Established Roles and permissions per
AWS guide: create dynamic contact forms for s3 static websites using aws lambda amazon api gateway and amazon ses
video titled: "Webinar: Dynamic Contact Forms for S3 Static Websites Using AWS Lambda, API Gateway & Amazon SES"
Client code, this is a very milk toast function being called to post the form on click.
function submitToAPI(event) {
event.preventDefault();
URL = "https://123abc.execute-api.us-east-1.amazonaws.com/prod/contact";
const namere = /[A-Za-z]{1}[A-Za-z]/;
const emailre = /^([\w-\.]+#([\w-]+\.)+[\w-]{2,6})?$/;
let fname = document.getElementById('first-name-input').value;
let lname = document.getElementById('last-name-input').value;
let email = document.getElementById('email-input').value;
let message = document.getElementById('message-input').value;
console.log(`first name: ${fname}, last name: ${lname}, email: ${email}\nmessage: ${message}`);
if (!namere.test(fname) || !namere.test(lname)) {
alert ("Name can not be less than 2 characters");
return;
}
if (email == "" || !emailre.test(email)) {
alert ("Please enter valid email address");
return;
}
if (message == "") {
alert ("Please enter a message");
return;
}
let data = {
fname : fname,
lname: lname,
email : email,
message : message
};
$.ajax(
{
type: "POST",
url : URL,
dataType: "json",
crossDomain: "true",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(data),
success: function () {
alert("Successful");
document.getElementById("contact-form").reset();
location.reload();
},
error: function () {
alert("Unsuccessful");
}
});
}
The problem was that the response in the lambda function had "Access-Control-Allow-Origin" set to "*".
This should have been set to the exact origin (no trailing slash), so if the origin is 'https://example.net', then the response in the lamda function should have "Access-Control-Allow-Origin" set to 'https://example.net' as shown below:
var response = {
"statusCode": 200,
"headers": {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "https://example.net"
},
"isBase64Encoded": false,
"body": "{ \"result\": \"Success\"\n}"
}```

How to add API key to Axios post request for mailchimp

I'm trying to set up an axios post request to add members to an audience list, but I can't figure out how to add the API key (keeps giving error 401: 'Your request did not include an API key.'). I've tried a bunch of things in the "Authorization" header, like what I put below (also: "Bearer ${mailchimpKey}", "${mailchimpKey}", "Bearer ${mailchimpKey}", "Basic ${mailchimpKey}", and probably more...).
I also don't know what the "username" would be, but "any" worked when I tested the API elsewhere.
Does anyone know how I should set this up?
axios
.post(
`https://${server}.api.mailchimp.com/3.0/lists/${list_id}/members`,
{
email_address: email,
status: "subscribed",
},
{
"User-Agent": "Request-Promise",
Connection: "keep-alive",
Authorization: `Basic any:${mailchimpKey}`,
// Testing on localhost
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type",
}
)
If your intention is to use HTTP Basic authentication, just use the Axios auth config option
axios.post(
`https://${server}.api.mailchimp.com/3.0/lists/${encodeURIComponent(list_id)}/members`,
{
email_address: email,
status: "subscribed",
},
{
auth: {
username: "anystring",
password: mailchimpKey
},
headers: { // personally, I wouldn't add any extra headers
"User-agent": "Request-Promise"
}
}
)
HTTP Basic auth headers look like
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
where the string after "Basic" is the Base64 encoded "username:password" string. Axios provides the auth option as a convenience so you don't need to encode the string yourself.
Some other problems you had were:
Adding request headers outside the headers config option
Attempting to send Access-Control-Allow-Origin and Access-Control-Allow-Headers as request headers. These are response headers only. Adding them to your request will most likely cause more CORS errors

How to send Query Params in Get Request in Robot Framework?

I am new to Robot Framework and am facing an issue while sending query params in Get Request method.
Following is the code that I tried with no luck :
Get Data With Filter
[Arguments] ${type} ${filter}
${auth} = Create List ${user_name} ${password}
${params} = Create Dictionary type=${type} filter=${filter}
Create Session testingapi url=${some_host_name} auth=${auth}
${resp} = Get Request testingapi /foo/data params=${params}
Log ${resp}
${type} has value new and ${filter} that I want is id:"1234"
I am expecting final url to formed as :
/foo/data?type=new&filter=id%3A1234
Instead of forming the expected url, I get the request url as :
GET Request using : uri=/foo/data, params={'type': 'new', 'filter': 'id:1234'}
I might be missing something very obvious but I cant figure out what it is. What can I change in this piece of code or any new code that needs to be added?
I think the logger is just outputting the params as the dictionary. The request should actually be made to foo/data?type=new&filter=id%3A1234
You can test it with the following request to Postman Echo (An HTTP testing service):
${auth} = Create List Mark SuperSecret
${params} = Create Dictionary type=Condos filter=2Bedrooms
Create Session testingapi url=http://postman-echo.com auth=${auth}
${resp} = Get Request testingapi /get params=${params}
${json} = To JSON ${resp.content} pretty_print=True
Log \n${json} console=yes
The response will correctly list the params you've encoded:
{
"args": {
"filter": "2Bedrooms",
"type": "Condos"
},
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, deflate",
"authorization": "Basic TWFyazpTdXBlclNlY3JldA==",
"host": "postman-echo.com",
"user-agent": "python-requests/2.25.0",
"x-amzn-trace-id": "Root=1-5fb43ae9-1880b0a621c864b06ce1f54a",
"x-forwarded-port": "80",
"x-forwarded-proto": "http"
},
"url": "http://postman-echo.com/get?type=Condos&filter=2Bedrooms"
}

SAPUI5 xhr request to Azure DevOps authorization failure

Experimenting with Azure DevOps using Postman and a SAPUI5 test application, essential knowledge of how xhr requests work. Managed to successfully read and update a Work Item in DevOps using Postman, however the latter step (update-PATCH) fails when I try to do it using SAPUI5 (read-GET worked). What I get is an authorization failure, telling me that I should use a token bearer authorization, problem is that I'm already doing it but seems to be ignored. Samples of (working) Postman and (non-working) SAPUI5 request headers along with the error returned to SAPUI5 anf the invocation call below. Having a look at them, issue SEEMS to be an authentication cookie sent from SAPUI5 which I can't remove at the moment. Any ideas?
PS: this is research work, in order to avoid CORS stuff, I'm running Chrome with no security option.
Postman Request Header (as shown in Postman, data body included):
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkhsQzBSMTJza3hOWjFXUXdtak9GXzZ0X3RERSIsImtpZCI6IkhsQzBSMTJza3hOWjFXUXdtak9GXzZ0X3RERSJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuYXp1cmUuY29tLyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0L2JkZWFlZGE4LWM4MWQtNDVjZS04NjNlLTUyMzJhNTM1YjdjYi8iLCJpYXQiOjE1ODIxMTQzNTYsIm5iZiI6MTU4MjExNDM1NiwiZXhwIjoxNTgyMTE4MjU2LCJhaW8iOiI0Mk5nWUdCL0Y4RCtXcUZuaG5QVTZkUTdHdGF5QUE9PSIsImFwcGlkIjoiZDU1M2E1NTctMjdjMy00MWQ3LWFiM2YtNzc4NDVjNDg3Y2VkIiwiYXBwaWRhY3IiOiIxIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvYmRlYWVkYTgtYzgxZC00NWNlLTg2M2UtNTIzMmE1MzViN2NiLyIsIm9pZCI6ImE4NDUyYmJiLWY3NmUtNDExZi05ZGFlLWU5YmZmOGRhZGIyZCIsInN1YiI6ImE4NDUyYmJiLWY3NmUtNDExZi05ZGFlLWU5YmZmOGRhZGIyZCIsInRpZCI6ImJkZWFlZGE4LWM4MWQtNDVjZS04NjNlLTUyMzJhNTM1YjdjYiIsInV0aSI6Im9wNXYzN1RvdVVlTXBFdTJaRFN1QUEiLCJ2ZXIiOiIxLjAifQ.euzljaai1dMHgPwmN5smOUTCBW0cK_i8kNPdi9wdhAQ17eGoX8tYg6RK8gufsY3aPo_WTLsouR8f_tTjt1BdmGmH4h0hNO7hlHkXMUQr2ZJfMwX1UhikcX91fVMUuSneqnaMo8EqqtBa3iROn1Pi_sN5v8sQPYtkJBwZaFx20SxbQu_dMjilw9ibPhv24GAMY_2z53lBegagqaCbPHR7e-g94363eZh6RlX0bBJhaoK5zj8G1U6xqdLyGSY1q1lWo3m1GTjAciWuF7zvSLqOpzAMhu9GkY07idKdHjKQefewOFygsuGzMWTPklGyzHqHkagzyeubZrIKA1Jpi6beSg' \
--header 'Content-Type: application/json-patch+json' \
--data-raw ' [{
"op": "replace",
"path": "/fields/System.Title",
"value": "The ability to restrict access for users who are on long term leave XXX"
}]
SAPUI5 Request Header (from Debugger "Network" tab)
:authority: XXXXXXXXXXXX.visualstudio.com
:method: PATCH
:path: /SAP/_apis/wit/workitems/8919?api-version=5.1
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-GB,en-US;q=0.9,en;q=0.8
authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkhsQzBSMTJza3hOWjFXUXdtak9GXzZ0X3RERSIsImtpZCI6IkhsQzBSMTJza3hOWjFXUXdtak9GXzZ0X3RERSJ9.eyJhdWQiOiIwMDAwMDAwMi0wMDAwLTAwMDAtYzAwMC0wMDAwMDAwMDAwMDAiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9iZGVhZWRhOC1jODFkLTQ1Y2UtODYzZS01MjMyYTUzNWI3Y2IvIiwiaWF0IjoxNTgyNTUyMjA0LCJuYmYiOjE1ODI1NTIyMDQsImV4cCI6MTU4MjU1NjEwNCwiYWlvIjoiNDJOZ1lKajRwV0s5OTBIcEV5YlQ5ZVpLV2lwdUFRQT0iLCJhcHBpZCI6ImQ1NTNhNTU3LTI3YzMtNDFkNy1hYjNmLTc3ODQ1YzQ4N2NlZCIsImFwcGlkYWNyIjoiMSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0L2JkZWFlZGE4LWM4MWQtNDVjZS04NjNlLTUyMzJhNTM1YjdjYi8iLCJvaWQiOiJhODQ1MmJiYi1mNzZlLTQxMWYtOWRhZS1lOWJmZjhkYWRiMmQiLCJzdWIiOiJhODQ1MmJiYi1mNzZlLTQxMWYtOWRhZS1lOWJmZjhkYWRiMmQiLCJ0ZW5hbnRfcmVnaW9uX3Njb3BlIjoiRVUiLCJ0aWQiOiJiZGVhZWRhOC1jODFkLTQ1Y2UtODYzZS01MjMyYTUzNWI3Y2IiLCJ1dGkiOiJkazJkaklvWlJFT0pUSTlzN0QyVkFBIiwidmVyIjoiMS4wIn0.jsUzsnVpz6WtkcmjnvS22_b8pTNQIpcLhA3bRuFaQUek1dPNwOS5K_7pqoqmJeQhmuY2TFoQ6Yx6GGgHf91eKXLhaABXc9TYHMr5UMcGf11mGfIUlDf9Si5kd5UP_HhyCVsSYAsPhihU9SutYzBK5Nw0pxPKLP27C2IUJ8qH0ax8Pid3czWkMQGZUkJtHiXB9ewo3fPOloRWVqsvHp9UbL1L5o9ErWZHxyBty_kaheNCWI-aoCUEFBqDO8kNK-JONS9qNQ7zGYYvkJMcMwpwYctxlso1-x81Um3EFGqkJbGCjT0vSNMlRrrPKI0vG4QLuLX4JTr91b08Nj3cv6zTng
content-length: 129
content-type: application/json-patch+json
cookie:SpsAuthenticatedUser=DisplayName=Grigorios%20Kampouroglou&aad=False;VstsSession=%7B%22PersistentSessionId%22%3A%222faed874-961a-4420-989e-b747711f4a13%22%2C%22PendingAuthenticationSessionId%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22CurrentAuthenticationSessionId%22%3A%22df72f060-60df-4490-9a89-5a291acc15b2%22%2C%22SignInState%22%3A%7B%22spsprodweu4.vssps.visualstudio.com%22%3A%7B%22LastSignInTick%22%3A637177215165345730%2C%22SignInCount%22%3A2%7D%7D%7D; FedAuth=77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48U2VjdXJpdHlDb250ZXh0VG9rZW4gcDE6SWQ9Il8wYmMyNzFmMC03NTllLTQ4NTYtODQ3MS1jMzBhNmM0NDFhOGUtN0M5N0VEMjBFREI4NjYyRTdBRkYzRTEyRDQ3RUI4QjQiIHhtbG5zOnAxPSJodHRwOi8vZG9jcy5vYXNpcy1vcGVuLm9yZy93c3MvMjAwNC8wMS9vYXNpcy0yMDA0MDEtd3NzLXdzc2VjdXJpdHktdXRpbGl0eS0xLjAueHNkIiB4bWxucz0iaHR0cDovL2RvY3Mub2FzaXMtb3Blbi5vcmcvd3Mtc3gvd3Mtc2VjdXJlY29udmVyc2F0aW9uLzIwMDUxMiI+PElkZW50aWZpZXI+dXJuOnV1aWQ6ODE1M2FmMGItNTY5OS00OWFjLTgwZmEtMjM0NjY2MzgyZTg2PC9JZGVudGlmaWVyPjxDb29raWUgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwNi8wNS9zZWN1cml0eSI+MFlkQ1daWk9tSTRBQVFBQUNvRHFhbnBTQzhmU09ZeDRLbE1naFBoNmtNOHAwMDJTNEV4ZG4wWFZFSEdNbzBBeE81NzZuaHBVeXYyYXBxWWZkTFVhV3luVUlXSkZ0SFZsa2VGcGxSdkNtK0NLbnJVRlV1NjI5LytSdUpCTEd3bDRNU3NKTVVwK215dXNUVDZ3aVhRa2JnN3Y5Q2ZoQVlGUDEwaytZaTh5L3VVQ2NTeWVhbGtxdWlIVHd2Rjh3ZlovOGRlU3YxS3R1VFRYRlhLbFdaWTlwMi8yOU1FeUw4elM1R2xBdVhNWjNUR0lQckl5SXNWNjQ3R3FOT3lOQ05OVmdZeGl2cmxnM0RuOHZLQkp1RCtaMzVOQ1Bmay9DcjBUbzh3c2hqa0dHUjFQNHcxSnpNVHJ6S2xoN2VJT2lOOVlLczV1L001V3hsVU83RFNYSU91SWE5L2Y4VmxvVjN1cm5MT3pTU2N1Q1MwTjZVRzhyU3pIeXc5Q1NFU21tcWV2ejI4QUM0ajV1dHJhLzdwREFBRUFBRnlIdVp3cVhESmVkNUt6T2dkYzIrRktNdHNTM3VyUHNQeHY3OVRiZVRMYTFYREdPNEVBbzJMa0VPN2kxMVBzZHJ0S1pVK25MbXJRZUlWc2xHYk41Q3RaUzBZK3oxOWpCNjVNaUtFZXNITXF4Q3FOWFh1bnJDaDkvZUNkWE9pZnllTVlxLzhwMldNWWhxMVI1cVhxeWR3RVRrVmREY2VNMy9yazJmN1dyQUs2dm1qdDhRbnlNVmhhbXdCdkpZWm9oQkxvV0hMaVlyMlc3clZUc1BGWmZOWkIrb29UY0RjUzNnUmtRWi9PbmN4OUMrbDVNNmxsb1J5QnhjeDgySmQ4UUE5Q25DcCtLYXRRYTZSRnhZenAzTjFKRHdmR3ZBQTE0emNueDZuUjAxL25PK2hYTW9ad2pwZ1ZqKytCNzIxYy9GSlk1bHRUQmhyQzVHZWVQK0M0Nnh2d0JBQUFmVjkrTVFEY0NzRVovWFYzSHpZdkN3bjhkY054ZDUvdUIreFRkKzU1ZldMczVraytCcEJESk5IUW5WelNXTFEvRnlaT3hGWGMvQ2U2ZnliSVZTajViY3A4Z1lKY1FNVzZCRlhhWEg2TXp4TGtBaFBxZ0VrNHBOMXJzcWxqOVFmWXY0UTNYNGhmSlMzMG1PZ25jYVFPZHpDSmlyRGlMMGR0NFN2ZVlOeEJlT1lTZTRDZjV1YWw1ZllWWjBweUhTQmR0ODltTGVLU2V3UGxMMmloL29kU0k5bi9NU3R5N3BtSnRTcWhDaG9VbWtyTmpVUnVYVVJ4dGZBTHhDTngzVDJhbnlUa3BUN1AzVjVOUEhFWVcvRGw0aUNXVGV5ZUFLOE5qUUVXc1A4aytWWU90UWZONU5o; FedAuth1=Z1FEWFk3TlA4UDV4NFZzZ0lmcFE5ZmNRTTNvR3g3K1E2N1ZCSTBVVnRhbWZSaEswN3ZjRGsrZXk0dE9XMXpvbFovR3pYaUM0Yk8zZnpjamFhZDJCMkNHbFpva1I3QXphQnFqQm5HdlBVcU8zVjNzSTd4THdsVVhGSS9Qak54OFBXZm5vMnhkM2F5dTZUaWhVZDFJY3R0ZXp6Nm45b0JqTkFXUDJCNWNjNERMT1IxOHBGdVR6YXFxMmo3K3Y1WDVnN2pRWnBHVVpFbUtOUWdVUnhMakRTK3M1Y0RaOUVBeXlEaXBTMktRbGY1dFk3MTVva3liU3hDUGhJVWlnQktFNEx2M0dmb0lpSzVGT0VKeTRWalY4MG4wRlB3V2lZblU0Yy9SRjI2NWlFM1Mzdzc2ZElqQlJKdXc2dU5EY0Jia3ZieWx2VWRuRnFpVm1MQnVYaWFtTW5FNUhEejNDTHNrUXBNaWZmNklaMWtzbkVkOEV6d0l1U1dhUnFNOG5xWXQyeGRTU1p5TXN6R04xeHJjbEM2bTU0Wi9XU3BjU3hHZlpwVExIa1FleERkYmlrMTZjRlI5RW1iTFdkaUhLb1dzaU9mMUJqOWNCcmpDRDIxVFROaS9WZmNiRjZxa0toWmRrczVxNlhsN2tLcC9yb2I4bjlyYXo0SDM1NTh6am51YjZNdDZJNnZNM3prZjhnMUs4dlhXR0FJbHhYVVhxMkNJdXdyUUtITGZuVE1veWMwajQzZCtlQXFJRkFBU3ZEZTdNb3I0MGYzSnVIQnF4elBWczNrUzNBU05BcWdad0JKY2F3U2YydnA0cE5DZ2YrTEdDVHhkSzJINzV6ZWJQbnh2WVQ5bDlQWXMyUW93bUVkU0Y5MXk5MSt1QTc4b2pwck94WSsrZE5UclczbDEwUjdIZm14L1RPVWpIUHQ3V1dKRjI5SmYrbzViVG0rZUZSOVlxQlBSanBLTm9xQW5RY2tuSEFQeFpLYWNwQVozaVNqOTBVa0EyMnNac2Z1MTdRTU9xd0k1SVNZbFh6d20xV3JDeDRYQ0VVOW9nK3ByajdROENzeFpqRVIzNjlTSitsLzIzc0hUa2t6eUpzV2RadUJSYzJhUWpoREFJK0tONVlGU3Z4TStMMUtSd29YQW5FaE1pcHRTaml0Z0RIaHF5N2Q0V2lNU3h6VmdVRXVCWTZVOTUzT0ErcDhXWmdaTlRqRDRHWFIvamFPOUNZWjJ4cHNTaURvRHBOeG9nUmMxbnpuVUNkcGsrZHpuNmN1dzZDY1dIYlgzUDdHWVVxcFJnRDFZUU5XSnVTdHdyZ2tOd2wzVDM0cWhJdEhhczRpdHVPb2pEMkJwY2hOb3dBM1FQblRFLy9tR216R1JPNkgwbEVCY2p6OE1JNmE5SVFsUjBxL1lqbGtWbStGS2RDY0dzTDlHOE05TVRHN3hsenYyK1hmSENDOEt6WEt5NjdDTGMxTW0rTTI1Q3NqMzBadS9xdTYranlYWDBwblVaNERHSjZ0bFk5c202WUkveDhDQWswSjkwQmg2UFF0YVdBYU1tQTJDNld4TytuVkp2SjVoVWhOWkxFYkk0dThiMGtXL3JOOGxzZnZFb1JEemUzdjFXcXZlVldUaGpPZTdZeWdUeVlkcmE1RGorUGVhenloMzBSNldXdGp0c2k1NlFldmpYLzZ3am1QNFJYR1Z3QURZcU1JTVFRcXFXOUhsbnVuWHBSYk85eVByZWV0S3p6UWw0aUQxNDV4N2phclY0U2JQb003bkdESmxia3VCV1A5RHNMUDVYb2hOQ2pyS0RpaDJ2bk9zSnVpWkZRN3liMVZwVG9qeUl3cUE9PTwvQ29va2llPjwvU2VjdXJpdHlDb250ZXh0VG9rZW4+; UserAuthentication=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6InpQVTRQb1VlNU1McFR2dWRGTmxaQXQ4Mkd4ayJ9.eyJmYW1pbHlfbmFtZSI6IkthbXBvdXJvZ2xvdSIsImdpdmVuX25hbWUiOiJHcmlnb3Jpb3MiLCJvaWQiOiIzZWY1OThmMi00MTk4LTQ1NDctYTM5Mi0zMmJhYTdkNTA4NTIiLCJ0aWQiOiJiZGVhZWRhOC1jODFkLTQ1Y2UtODYzZS01MjMyYTUzNWI3Y2IiLCJzdWIiOiJiZGVhZWRhOC1jODFkLTQ1Y2UtODYzZS01MjMyYTUzNWI3Y2JcXHVpdGdrYUBsZWVkcy5hYy51ayIsInVuaXF1ZV9uYW1lIjoidWl0Z2thQGxlZWRzLmFjLnVrIiwiZW1haWwiOiJ1aXRna2FAbGVlZHMuYWMudWsiLCJwdWlkIjoiYWFkOjEwMDMzRkZGQTNBRkZENEQiLCJ2ZXIiOiIxLjAiLCJqdGkiOiJmOGQ1ZDczNS1hNjNkLTQ5N2QtYWNjNi0xZTBmYTUwM2E4NmQiLCJpc3MiOiJhcHAudnN0b2tlbi52aXN1YWxzdHVkaW8uY29tIiwiYXVkIjoiZTVjODY2NzYtZDA2My00ZGEzLWJiOTYtYzhlMDUwNGJkYmE1IiwibmJmIjoxNTgyNTQ5NjY5LCJleHAiOjE1ODMxNTQ0Njl9.DDrwADcUeMCB-Tt9sLu6T042hel7aTdm8IfUmQY7pHOkT9VPQSAhVE-Puw3Y8dzfnzteIhojaSEsVI17pjGblOuDbCVcb9LzJ17u-XCmD2SY2M6i-t_xOaj-daYy2tRigVpN-lCoQ-K9VcF7mkHH4hiFynHUQDMcUn7gV9xs7zDCE4ILbDvnltKfFvcn0wQP0BxJwurhK8PaDhSPrr1fm-b38zmYB8nGEaYiobDdX8ZSOxMnlEUivoRkogGp51nSHZzexI3ER7TDJRMPSVkTeaIiatoWWjli8AlPewMKM46Ulb6TtbC4liBrqFnY46dTA-aSvb0oyNCynJi89b2yXw
origin: https://webidetesting4693883-af5c37dc2.dispatcher.hana.ondemand.com
referer: https://webidetesting4693883-af5c37dc2.dispatcher.hana.ondemand.com/webapp/index.html?hc_orionpath=%2FDI_webide_di_workspace92fzelc13935in9e%2FTest_space&neo-di-affinity=BIGipServerdisapwebide.hana.ondemand.com+%21MfjRbGTQMxtzeMH2sXeD7QV2Vba36qePi57x9XciOdsuGVAcQO4JzpULTwOmB5brhKtfSMM9EVgn%2FK0%3D&origional-url=index.html&sap-ui-appCacheBuster=..%2F&sap-ui-xx-componentPreload=off
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36
Error response
"{"$id":"1","innerException":null,"message":"A cross-origin request from origin \"https://webidetesting4693883-af5c37dc2.dispatcher.hana.ondemand.com\" is not allowed when using cookie-based authentication. An authentication token needs to be provided in the Authorization header of the request.","typeName":"Microsoft.VisualStudio.Services.WebApi.VssApiUnsafeCrossOriginRequestException, Microsoft.VisualStudio.Services.WebApi","typeKey":"VssApiUnsafeCrossOriginRequestException","errorCode":0,"eventId":3000}"
SAPUI5 code
_updateWorkItem: function() {
var promise = $.Deferred();
var self = this;
url = "https://login.microsoftonline.com/bdeaeda8-c81d-45ce-863e-5232a535b7cb/oauth2/token";
$.ajax({
url: url,
headers: {"Content-Type": "application/x-www-form-urlencoded"
},
type: "POST",
dataType: "json",
data: {
"grant_type": "client_credentials",
"client_id": "d553a557-27c3-41d7-ab3f-77845c487ced",
"client_secret": "53GH[jL6VqID#cp]DQ[wMS5#Smx]0l80"
},
success: function(xhrData) {
var json= [{
"op": "replace",
"path": "/fields/System.Title",
"value": self.getView().byId("sTitle").getValue().toString()
}];
sDevOpsToken = xhrData.access_token;
url = "https://XXXXXXXXXXXX.visualstudio.com/SAP/_apis/wit/workitems/" + oModel.getProperty("/id").toString() +"?api-version=5.1";
$.ajax({
url: url,
headers: {"Content-Type": "application/json-patch+json",
"Cookie": null
},
type: "PATCH",
data: JSON.stringify(json),
cache: false,
dataType: "application/json-patch+json",
beforeSend: function (xhr) {
//xhr.setRequestHeader("Authorization", "Basic " + btoa("" + ":" + "{sDevOpsToken}"));
//xhr.setRequestHeader("Authorization", "Bearer " + btoa(sDevOpsToken));
xhr.setRequestHeader("Authorization", "Bearer " + sDevOpsToken);
},
success: function(xhrData2) {
oModel.setProperty("/Title", self.getView().byId("sTitle").getValue().toString());
promise.resolve();
},
error: function(xhrData2) {
MessageBox.error(xhrData2.response);
promise.resolve();
}
});
}
});
var readyToGo = function() {
};
jQuery.when(promise).done().then( jQuery.proxy(readyToGo, this) );
}

Different authorization header for each operation in a Guzzle client service description

The API I'm accessing requires a custom authorization header that is a combination of the publicKey that is passed in when the client is instantiated and the complete URI of the API endpoint. I want to pull the baseUrl and operation uri out of the service description and use them to create the authorization header, but I can't figure out how to do this when calling the instantiated client.
This is the service description:
{
"name": "FranchiseSystem",
"apiVersion": "1",
"baseUrl": "https://apidev.example.com",
"description": "REST API client",
"operations": {
"GetFranchiseList": {
"httpMethod": "GET",
"uri": "v1/franchise",
"summary": "Returns an array of franchises."
},
"GetReviews": {
"httpMethod": "GET",
"uri": "v1/review",
"summary": "Returns an array of reviews."
}
}
}
This is the client setup:
$testClient = new JunknetClient([
'publicKey' => '1234567890',
]);
This is the call to the instantiated client with the name of the operation:
$result = $testClient->GetFranchiseList();
or:
$result = $testClient->GetReviews();
When testClient->GetFranchiseList is called, I need to create the authorization header using the publicKey and the values of baseUrl and uri for GetFranchiseList.
When testClient->GetReviews is called, I need to create the authorization header using the publicKey and the values of baseUrl and uri for GetReviews.
You might want to have a look at the following links from the Guzzle docs.
Request Options - Headers
Authentication Parameters
I was able to solve my problem by using and event emitter and subscriber. It's a bit messy, but it get's the job done.
private function handleCredentialsOptions(Collection $config) {
//Build authorization header from $config values
$this->getHttpClient()->getEmitter()->on('before',
function (BeforeEvent $e) use(&$config) {
$this->getHttpClient()->setDefaultOption('headers', [
'Authentication' => '',
]);
$path = $e->getRequest()->getUrl();
$authValue = $config['publicKey'].';;';
$authValue .= time().';';
$authValue .= strtoupper(md5($config['privateKey'] . $path));
$this->getHttpClient()->setDefaultOption('headers', [
'Authentication' => $authValue,
]);
});
}