How to use two calls on the same session in flurl - session

I want to use GetAsync to get a token then to use that token in a POST function. Both Get and Post should be made on same session.
Here is the GET function:
var result = await SA_BaseUrl
.AppendPathSegments("ProdOrderConfSet")
.WithBasicAuth("UserName", "Password")
.WithHeader("Accept","application/json")
.WithHeader("X_CSRF_Token", "fetch")
.GetAsync();
IReadOnlyNameValueList<string> headers = result.Headers;
string X_CSRF_Token = headers.FirstOrDefault(h => h.Name == "x-csrf-token").Value;
And Post function:
var result2 = await SA_BaseUrl
.AppendPathSegments("ProdOrderConfSet")
.WithBasicAuth("UserName", "Password")
.WithHeader("Accept","application/json")
.WithHeader("Content-Type", "application/json")
.WithHeader("X_CSRF_Token", X_CSRF_Token)
.PostJsonAsync(workStep)
.ReceiveJson<DANTESAP_ProdWorkStep>();
Running the above code, I am getting:
403 Forbidden, CSRF token validation failed
How can I run the two functions on the same session?
Unfortunately, there is no documentation for the service I am trying to reach. But when I use Postman, it works without any problem. I do not know what is missing (or wrong) in my C# code.
Here is the Get function in order to get the token:
And here is the POST function that uses the extracted csrf token from the GET function:

Get the cookies and re-use them:
var result = await SA_BaseUrl
.AppendPathSegments("ProdOrderConfSet")
.WithBasicAuth("UserName", "Password")
.WithHeader("Accept","application/json")
.WithHeader("X_CSRF_Token", "fetch")
.WithCookies(out var jar)
.GetAsync();
...
var result2 = await SA_BaseUrl
.AppendPathSegments("ProdOrderConfSet")
.WithBasicAuth("UserName", "Password")
.WithHeader("Accept","application/json")
.WithHeader("Content-Type", "application/json")
.WithHeader("X_CSRF_Token", X_CSRF_Token)
.WithCookies(jar)
.PostJsonAsync(workStep)
.ReceiveJson<DANTESAP_ProdWorkStep>();

Related

Is Single Sender Validation in Sendgrid possible without logging in?

Was just wondering if it's possible for Single Sender Validation to be completed without having to login to Sendgrid as part of the process (e.g. click-through without login). For context, sometimes the people who "own" a mail address that we want to use for sending don't have access to Sendgrid, and we'd like them to be able to validate it. I think they can't by design, but wanted to confirm.
Looking at the API documentation, it looks like you can use the token sent in the validation email to complete the validation process, but I'm not sure if there's any way to effectively make use of that to redirect the user back to a process we control. There's another post that mentions the same kind of challenge, but thought I'd ask again as there wasn't anything definitive.
Is there a simple way to have the user who receives the validation redirect back to something other than sendgrid directly?
Thanks in advance!
The only alternative to logging in is to use the SendGrid API.
First, you either request the verification using the UI, or you use the Create Verified Sender Request API to start the verification for the single sender.
Then, the verification email will be sent to the specified email address which contains the verification URL. Usually, this URL will redirect you the the actual URL containing the verification token, as mentioned in the SO post you linked.
Once you get the verification token, you can use the Verify Sender Request API, passing in the verification token, to verify the single sender.
Note: All these APIs require a SendGrid API key.
So technically, you could have an application that prompts your user for their email address to verify, then uses the SendGrid API to start the verification which sends the verification email, then ask the user to go to their email inbox and copy in their verification link, then let the user paste in the URL from which you can extract the verification token, and use the API to verify. While the user didn't have to log in, it still requires some manual work.
However, the inputting of the email address and the checking the email inbox can also be done programmatically, so this process can be 100% automated, although it takes quite a bit of programming.
Here's a C# sample:
using System.Net;
using Microsoft.AspNetCore.WebUtilities;
using SendGrid;
namespace VerifySender;
internal class Program
{
public static async Task Main(string[] args)
{
var configuration = new ConfigurationBuilder()
.AddUserSecrets<Program>(optional: true)
.Build();
var apiKey = configuration["SendGrid:ApiKey"]
?? Environment.GetEnvironmentVariable("SENDGRID_API_KEY")
?? throw new Exception("SendGrid API Key not configured.");
var client = new SendGridClient(apiKey);
// replace this JSON with your own values
const string data = """
{
"nickname": "Orders",
"from_email": "orders#example.com",
"from_name": "Example Orders",
"reply_to": "orders#example.com",
"reply_to_name": "Example Orders",
"address": "1234 Fake St",
"address2": "PO Box 1234",
"state": "CA",
"city": "San Francisco",
"country": "USA",
"zip": "94105"
}
""";
var response = await client.RequestAsync(
method: SendGridClient.Method.POST,
urlPath: "verified_senders",
requestBody: data
);
if (!response.IsSuccessStatusCode)
{
Console.WriteLine($"Failed to request sender verification. HTTP status code {response.StatusCode}.");
Console.WriteLine(await response.Body.ReadAsStringAsync());
Console.WriteLine(response.Headers.ToString());
}
Console.WriteLine("Enter verification URL:");
var verificationUrl = Console.ReadLine();
var token = await GetVerificationTokenFromUrl(verificationUrl);
response = await client.RequestAsync(
method: SendGridClient.Method.GET,
urlPath: $"verified_senders/verify/{token}"
);
if (!response.IsSuccessStatusCode)
{
Console.WriteLine($"Failed to verify sender. HTTP status code {response.StatusCode}.");
Console.WriteLine(await response.Body.ReadAsStringAsync());
Console.WriteLine(response.Headers.ToString());
}
}
private static async Task<string> GetVerificationTokenFromUrl(string url)
{
/*
* url could be three different types:
* 1. Click Tracking Link which responds with HTTP Found and Location header to url type 2.
* 2. URL containing the verification token:
* https://app.sendgrid.com/settings/sender_auth/senders/verify?token=[VERIFICATION_TOKEN]&etc=etc
* 3. URL prompting the user to login, but contains url 2. in the redirect_to parameter:
* https://app.sendgrid.com/login?redirect_to=[URL_TYPE_2_ENCODED]
*/
const string verificationBaseUrl = "https://app.sendgrid.com/settings/sender_auth/senders/verify";
const string loginBaseUrl = "https://app.sendgrid.com/login";
if (url.StartsWith(verificationBaseUrl))
{
var uri = new Uri(url, UriKind.Absolute);
var parameters = QueryHelpers.ParseQuery(uri.Query);
if (parameters.ContainsKey("token"))
{
return parameters["token"].ToString();
}
throw new Exception("Did not find token in verification URL.");
}
if (url.StartsWith(loginBaseUrl))
{
var uri = new Uri(url, UriKind.Absolute);
var parameters = QueryHelpers.ParseQuery(uri.Query);
if (parameters.ContainsKey("redirect_to"))
{
url = $"https://app.sendgrid.com{parameters["redirect_to"]}";
return await GetVerificationTokenFromUrl(url);
}
throw new Exception("Did not find token in verification URL.");
}
var clientHandler = new HttpClientHandler();
clientHandler.AllowAutoRedirect = false;
using var httpClient = new HttpClient(clientHandler);
var response = await httpClient.GetAsync(url);
if (response.StatusCode == HttpStatusCode.Found)
{
var uri = response.Headers.Location;
return await GetVerificationTokenFromUrl(uri.ToString());
}
throw new Exception("Did not find token in verification URL.");
}
}
Take note of the comments inside of GetVerificationTokenFromUrl. Since I don't trust the user to copy the URL from the email without clicking on it, I added support for three types of URL:
Click Tracking Link which responds with HTTP Found and Location header to url type 2.
URL containing the verification token: https://app.sendgrid.com/settings/sender_auth/senders/verify?token=[VERIFICATION_TOKEN]&etc=etc
URL prompting the user to login, but contains url 2. in the redirect_to parameter: https://app.sendgrid.com/login?redirect_to=[URL_TYPE_2_ENCODED]
Here's the full source code on GitHub.

Google Push notification giving ParseError

I am trying to use google push notification for calendar to be notified if a user's event's start or/and end dateTime changes.
I have followed all the steps from push doc regarding registering and verifying my domain.
My code is as follows:
#blueprint.route("/notifications", methods={'GET','POST'})
def timeBlocker():
email = '....#gmail.com'
user = User.query.filter_by(email=email).first()
thecredentials = {
'client_id': os.getenv('client_id'),
'client_secret':os.getenv('client_secret'),
'refresh_token':user.refresh,
'grant_type': 'refresh_token',
}
req = requests.post(url='https://oauth2.googleapis.com/token', data = thecredentials)
req_ = req.json()
accessToken = req_["access_token"]
print('access token is ' + accessToken)
body = {
'id': '01234567-89ab-cdef-0123456789ab',
'type': 'web_hook',
'address': 'https://dayliii.com/notifications'
}
headers = {'Authorization': 'Bearer ' + accessToken,
'Content-Type': 'application/json'
}
calendar = '....#group.calendar.google.com'
req = requests.post(url='https://www.googleapis.com/calendar/v3/calendars/....#group.calendar.google.com/events/watch', data = body, headers=headers)
return str(req.json())
Error:
{'error': {'errors': [{'domain': 'global', 'reason': 'parseError', 'message': 'Parse Error'}], 'code': 400, 'message': 'Parse Error'}}
I tried converting from double quotes to single quote as this similar post suggested yet it didn't work.
Lastly, I was curious to know if I should register & verify domain ownership of 'http://localhost:5000/' when working with push notifications in dev mode? As that's the error I am expecting to get that not sure about the way around it.
The data parameter in request() function accepts json format.
You can try converting your body variable into a json string using json.dumps().
Your request code should look like this:
req = requests.post(url='https://www.googleapis.com/calendar/v3/calendars/....#group.calendar.google.com/events/watch', data = json.dumps(body), headers=headers)

Calling rest server from mobile app

Following on from https://lists.hyperledger.org/g/composer/message/91
I have adapted the methodology described by Caroline Church in my IOS app.
Again I can authenticate with google but still get a 401 authorization error when POSTing.
I have added the withCredentials parameter to the http header in my POST request.
does the rest server pass back the token in cookie ? I don't receive anything back from the rest server.
where does the withCredentials get the credentials from ?
COMPOSER_PROVIDERS as follows
COMPOSER_PROVIDERS='{
"google": {
"provider": "google",
"module": "passport-google-oauth2",
"clientID": "93505970627.apps.googleusercontent.com",
"clientSecret": "",
"authPath": "/auth/google",
"callbackURL": "/auth/google/callback",
"scope": "https://www.googleapis.com/auth/plus.login",
"successRedirect": "myAuth://",
"failureRedirect": "/"
}
}'
the successRedirect points back to my App. After successfully authenticating I return to the App.
Got this working now. The App first authenticates with google then exchanges the authorization code with the rest server.
The Rest server COMPOSER_PROVIDERS needs to be changed to relate back to the app.
clientID is the apps ID in google,
callbackURL and successRedirect are reversed_clientID://
The App calls http://localhost:3000/auth/google/callback with the authorization code as a parameter.
this call will fail, but an access_token cookie is written back containing the access token required for the rest server.
The user id of the logged in user is not passed back, when exchanging the code for a token with google we get back a JWT with the details of the logged in user. We need this back from the rest server as well as the token. Is there any way to get this ?
changing the COMPOSER_PROVIDERS means that the explorer interface to the Rest server no longer works.
func getRestToken(code: String) {
let tokenURL = "http://localhost:3000/auth/google/callback?code=" + code
let url = URL(string:tokenURL);
var request = URLRequest(url: url!);
request.httpMethod = "GET";
request.setValue("localhost:3000", forHTTPHeaderField: "Host");
request.setValue("text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8", forHTTPHeaderField: "Accept");
request.setValue("1", forHTTPHeaderField: "Upgrade-Insecure-Requests");
request.httpShouldHandleCookies = true;
request.httpShouldUsePipelining = true;
let session = URLSession.init(configuration: .default);
session.configuration.httpCookieAcceptPolicy = .always;
session.configuration.httpShouldSetCookies=true;
session.configuration.httpCookieStorage = HTTPCookieStorage.shared;
let task = session.dataTask(with: request) { (data, response, error) in
var authCookie: HTTPCookie? = nil;
let sharedCookieStorage = HTTPCookieStorage.shared.cookies;
// test for access_token
for cookie in sharedCookieStorage! {
if cookie.name == "access_token"
{
print(“Received access token”)
}
}
guard error == nil else {
print("HTTP request failed \(error?.localizedDescription ?? "ERROR")")
return
}
guard let response = response as? HTTPURLResponse else {
print("Non-HTTP response")
return
}
guard let data = data else {
print("HTTP response data is empty")
return
}
if response.statusCode != 200 {
// server replied with an error
let responseText: String? = String(data: data, encoding: String.Encoding.utf8)
if response.statusCode == 401 {
// "401 Unauthorized" generally indicates there is an issue with the authorization
print("Error 401");
} else {
print("HTTP: \(response.statusCode), Response: \(responseText ?? "RESPONSE_TEXT")")
}
return
}
}
task.resume()
}
have you authorised the redirect URI in your Google OAUTH2 configuration ?
This determines where the API server redirects the user, after the user completes the authorization flow. The value must exactly match one of the redirect_uri values listed for your project in the API Console. Note that the http or https scheme, case, and trailing slash ('/') must all match.
This is an example of an Angular 5 successfully using it Angular 5, httpclient ignores set cookie in post in particular the answer at the bottom
Scope controls the set of resources and operations that an access token permits. During the access-token request, your application sends one or more values in the scope parameter.
see https://developers.google.com/identity/protocols/OAuth2
The withCredentials option is set, in order to create a cookie, to pass the authentication token, to the REST server.
Finally this resource may help you https://hackernoon.com/adding-oauth2-to-mobile-android-and-ios-clients-using-the-appauth-sdk-f8562f90ecff

how to handle token authentication in Angular Dart?

First time dealing with a SPA. I have a back-end restful service that returns a token when a user signs in. I know I am supposed to send the token through the headers in each request so I was thinking in saving the token in a file and create a service or a class that loads the token in every component but I don't know if this is a good approach as I can't find documentation for Angular Dart about this.
I saved the Token first in localStorage as Tobe O suggested:
Future login(username, password) async {
String url = 'http://127.0.0.1:8000/auth/login/';
var response =
await _client.post(url, body: {'username': username, 'password': password});
Map mapped_response = _decoder.convert(response.body);
window.localStorage.addAll({"token": mapped_response["key"]});
}
But still I was receiving 401 responses when I tried to get user information, this was the function:
Future check_authentification () async {
String _headers_key = "Authorization";
String _headers_value = "Token "+window.localStorage["token"];
var response = await _client.get("http://127.0.0.1:8000/auth/user/", headers: {_headers_key: _headers_value});
user_data = _decoder.convert(response.body);
response_status = response.statusCode;
}
I couldn't get authorized because django-rest-auth wasn't properly configured for token authorization. The solution was to add TokenAuthentication to the default authentication classes in django settings.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
)}

How to parameterize Bearer token authorization in Jmeter

I have a jmeter login script where user logs in and logs out. The detailed screenshots are attached below.
Request data is as attached:
In the response date , the authorization token is generated:
And the regular expression for the same is as below:
I am passing the value as parameter in 55/users:
When I'm running the script it is failing:
Here is the response data:
Use Header Manager to pass the Token as a Header so you would have:
See for more details:
https://stackoverflow.com/a/43283700/460802
If you're looking to learn jmeter correctly, this book will help you.
A bit easier JMeter setup (login/get):
Thread Group
HTTP Request, Body Data: { "Login":"some", "Password":"credentials" }
HTTP Header Manager: content-type application/json
JSON Extractor - Names of created variables: Token; JSON Path expression: tokenName (root level in my case)
HTTP Request
HTTP Header Manager: content-type -> application/json; Authorization -> Bearer ${Token}
Response Assertion: Fields to Test = Response Code; Pattern Matching Rules = Equals, Not; Pattern to Test 401
View Results Tree to check results
Local IE Ajax version in case...
<SCRIPT>
var baseUri = 'https://localhost:port';
var tokenUri = '/something';
var getUri = '/restrictedData';
var token;
var form = { "Login":"some", "Password":"credentials" };
postRequest(baseUri + tokenUri, form, gotToken)
function gotToken(progress) {
var response = progress.srcElement;
if (response.status != 200) {
document.body.innerText = "Error:\n" + response.response;
return;
}
token = JSON.parse(response.response);
console.log(JSON.stringify(token));
var restricted = getRequest(baseUri + getUri, token.tokenName, gotRestricted);
}
function gotRestricted(progress) {
var jsonStr = progress.srcElement.response;
var jsonObj = JSON.parse(jsonStr);
document.body.innerText = JSON.stringify(token,null,2) + '\n\n' + JSON.stringify(jsonObj,null,2);
}
function getRequest(url, token, callback) {
var xhr = new XMLHttpRequest();
xhr.onloadend = callback;
xhr.open('GET', url);
xhr.setRequestHeader('contentType', 'application/json')
if (token) xhr.setRequestHeader("Authorization", "Bearer " + token);
xhr.send();
return xhr;
}
function postRequest(url, body, callback) {
var xhr = new XMLHttpRequest();
xhr.onloadend = callback;
xhr.open('POST', url);
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(JSON.stringify(body));
return xhr;
}
</SCRIPT>
Add Bearer ${token} in HTTP Header Manager available under failing HTTP Request.
If you already have the bearer token and just want to use in in header manager then,
in HTTP HEADER MANAGER tab, put these values under NAME and VALUE column respectively.
Name: Authorization
Value: Bearer "add your actual token without quotes"
Once you've extracted the token from the token API request, use this token in the HTTP Authorization Header manager for subsequent API's. Example below:
Header Name: Header Value Authorization: Bearer ${generated_token}
Where "generated_token" is a variable containing the extracted token.
I got cUrl from my API and then I imported it.
use Authorization as parameter name and value should be
Bearer ${variable_name}

Resources