X-CSRF-TOKEN validation failed in SAPUI5 - sapui5

I am calling a create service of SAP Net weaver Gateway from SAPUI5. I have written following code for getting CSRF but I am not able to get it. It asks me to enter the username and password as shown in the image.
Code:
function onSave()
{
useroDataModel = newsap.ui.model.odata.ODataModel("proxy/sap/opu/odata/sap/ZUI_GROUP1_CREATE");
empid = oTF2.getValue();
empname = oTF1.getValue();
empaddr = oTF.getValue();
empdoj = oDP.getValue();
uilogon();
useroDataModel.read("/zui_group1_createCollection(im_emp_id='"+empid+"')", null, null, true, fnSuccess, fnError);
useroDataModel.setHeaders({
"X-CSRF-Token": "Fetch" // auth
});
function fnSuccess(data,response)
{
//alert(response.headers['x-csrf-token']);
var header_xcsrf_token = response.headers['x-csrf-token'];
//alert(header_xcsrf_token);
var createrequestdata = {
im_emp_id : empid,
im_emp_name : empname(),
im_emp_addr : empaddr(),
im_emp_doj : empdoj()
};
useroDataModel.setHeaders({
"X-Requested-With": "XMLHttpRequest",
"Content-Type": "application/atom+xml",
"DataServiceVersion": "2.0",
"Accept": "application/atom+xml,application/atomsvc+xml,application/xml",
"X-CSRF-Token": header_xcsrf_token
});
useroDataModel.create("/zui_g2_createCollection", createrequestdata, null, fnS, fnE);
function fnS(response){
if(response.ex_status == "Entry Created.")
{
alert("Created.");
}
else
{
alert("Failed.");
}
}
function fnE(Error){
alert("error in create"+Error.message);
}
}
function fnError(oError)
{
alert("Error in read"+oError.message);
}
}
function uilogon()
{
var tok = "username" + ':' + "password";
var hash = btoa(tok);
auth = "Basic" + hash;
// alert(auth);
// Save to Local Storage
// $.sap.require("jquery.sap.storage");
// var UI5Storage = $.sap.storage(jQuery.sap.storage.Type.session);
// UI5Storage.remove("Auth");
// UI5Storage.put("Auth",auth);
useroDataModel.setHeaders({
//'Accept-Encoding': "gzip",
"Authorization" : auth});
// alert("dne");
}
I am able to fetch the CSRF-TOKEN in auth variable. But it asks me for following authentication in which asks me to enter the username and password of SAP NET WEAVER GATEWAY but if I enter the username and password through which I am logged in, it does not accept.

If you want to use your method of authentication you will need to authenticate prior to the ODataModel instantiation, you cant read the metadata let alone fetch a CSRF token unless authenticated, also you need to fetch the token prior to doing the POST.
Why not pass the username and password into the constructor of the ODataModel
var oModel = new sap.ui.model.odata.ODataModel(sServiceUrl, bJSON, sUser, sPwd);
once authenticated if you are using binding functionality the CSRF security token will be read for you else if you want to use oModel.read you can do it manually
oModel.refreshSecurityToken()

Related

Flutter qraphQl issue with setting requesting data from body of api

I am trying to connect to an graphQl api that uses the token as the password in the Basic auth section of the header. I have tried using flutter_graphql but as I only get the token back after the user logs in. I have managed to get logged in using:
String username = "";
String password = token;
String basicAuth = 'Basic' + base64Encode(utf8.encode("$username:$password"));
String projects = "query Projects{Projects{id name}}";
Uri newUri = Uri.parse("$link");
var newResponse = await http.post(newUri, headers: {
"Authorization": basicAuth,
"Content-Type": "application/graphql"
}, body: //I need to get projects here.
);
var newNonJsonData = newResponse.body;
group("Testing the graph ql data after logging in: ", () {
test("Logged in", () {
expect(newResponse.statusCode, 200);
});
test("getting the data from the api", () {
print("non json return:" + newNonJsonData);
});
});
I have tried to set the body as
jsonEncode({
'query' : prjects
})
but the moment I request the data it asks to log in.
Please could someone help!!!

Securing REST API with JWT access_token and refresh token approach

I'm building a web application using the MERN stack. I've made a REST API to interact with my front-end the usual way,but I'm not able to figure out the best way to build a secure API and overall security of the application.
So far this is what I've tried
Flow of authenticating a user/request :
1. User enters the credentials
2. Server responds with access_token and refresh_token, caching refresh_token in redis cache with email as key and access_token in localStorage
3. To access a protected route, user sends the request with Bearer {ACCESS_TOKEN} in request header
4. Server checks if the token is valid and not expired, serving the user back with protected resource
5. In case, the access_token is expired (i've kept the token expiry short eg. 5 min), an action is fired from the front-end (using redux actions), a sample request :
POST http://localhost:3000/user/token
Header Bearer {ACCESS_TOKEN}
Body
{
"email" : "user#example.com"
}
Server performs a check in redis cache if the email has refresh_token
If yes, server responds with updated access_token
This is how I'm signing the tokens
const signToken = user => {
let email = user.email;
let name = user.name;
const accessToken = JWT.sign({
iss : process.env.APP_NAME,
sub : user.id,
email : email,
name : name
}, JWT_SECRET, {
expiresIn : 300
});
const refreshToken = JWT.sign({
iss : process.env.APP_NAME,
sub : user.id,
email : email,
name : name
}, REFRESH_TOKEN_SECRET, {
expiresIn : '30d'
});
// Save to redis cache
REDIS_CLIENT.set(email, refreshToken);
return {accessToken, refreshToken};
}
and for getting new access_token
// Refresh token
const refreshToken = (req, res, next) => {
const extractToken = req.headers['authorization'];
const token = extractToken.split(' ')[1];
if (!token) {
return res.status(403).json({
message : 'Unauthorized'
});
}
REDIS_CLIENT.get(req.body.email, (err, cachedToken) => {
if (err) return res.status(500).json({message : 'Something went wrong'});
if (cachedToken == null) {
return res.status(403).json({message : 'Unauthroized'});
} else {
JWT.verify(cachedToken, REFRESH_TOKEN_SECRET, (err, rt) => {
if (err) {
return res.status(500).json({message : 'Something went wrong'})
} else {
// Generate a new access token here
const newAccessToken = JWT.sign({
iss : process.env.APP_NAME,
sub : rt.sub,
email : rt.email,
name : rt.name
}, JWT_SECRET, {
expiresIn : 300
});
return res.json({
"accessToken" : newAccessToken
});
}
});
}
});
}
Is this approach secure? If not, what are some good ways to design the authentication flow if stack is MERN. Upon searching the internet, many have advised to set short expiry in access_token and use the refresh_token to generate new access_token, but I haven't found how to logout user on inactivity? What if attacker gets the expired token and email id, and generates the new access_token? How will be the oAuth integration?
PS : Sorry for putting so much here, came here after a lot of searches on the internet but found nothing much

How to use the Gmail API, OAuth2 for Apps Script, and Domain-Wide Delegation to set email signatures for users' alias in a G Suite domain

This is a continuation of this question: How to use the Gmail API, OAuth2 for Apps Script, and Domain-Wide Delegation to set email signatures for users in a G Suite domain
It showed a way to set a signature for another account, using Oauth2, Apps Script, and domain wide delegation.
However, it was not working for me when I have this scenario: I have a domain alias in our G-Suite account where myuser#aliasdomain.com is an alias for myuser#maindomain.com. I want to set a signature for myuser#aliasdomain.com. The example from the prior question only did myuser#maindomain.com.
Is it possible?
I tried this (modified from prior question's example code):
var credentials = {
"type": "service_account",
"project_id": "project-id-4606494xxxxxxxxx3",
"private_key_id": "8481966716a20fe34615daxxxxxxxxa",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXbOAiODt\n-----END PRIVATE KEY-----\n",
"client_email": "xxxxxxxxxxxx#project-id-46064949xxxxxxxxxxxx.iam.gserviceaccount.com",
"client_id": "112076306220190xxxxxxxxxx",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/xxxxxxxxxxxx%40project-id-4606494951xxxxxxxxxxxxxx.iam.gserviceaccount.com"
}
function setSignatureTest() {
var loginEmail = 'myuser#maindomain.com';
var sendAsEmail = 'myuser#aliasdomain.com';
var signature = 'test for awesome signature';
var test = setSignature(loginEmail, sendAsEmail, signature);
Logger.log('test result: ' + test);
}
function setSignature(loginEmail, sendAsEmail, signature) {
Logger.log('starting setSignature');
var signatureSetSuccessfully = false;
var service = getDomainWideDelegationService('Gmail: ', 'https://www.googleapis.com/auth/gmail.settings.basic', loginEmail);
if (!service.hasAccess()) {
Logger.log('failed to authenticate as user ' + loginEmail);
Logger.log(service.getLastError());
signatureSetSuccessfully = service.getLastError();
return signatureSetSuccessfully;
} else Logger.log('successfully authenticated as user ' + loginEmail);
var resource = { signature: signature };
var requestBody = {};
requestBody.headers = {'Authorization': 'Bearer ' + service.getAccessToken()};
requestBody.contentType = "application/json";
requestBody.method = "PUT";
requestBody.payload = JSON.stringify(resource);
requestBody.muteHttpExceptions = false;
var loginEmailForUrl = encodeURIComponent(loginEmail);
var sendAsEmailForUrl = encodeURIComponent(sendAsEmail);
var url = 'https://www.googleapis.com/gmail/v1/users/' + loginEmailForUrl + '/settings/sendAs/' + sendAsEmailForUrl;
var maxSetSignatureAttempts = 10;
var currentSetSignatureAttempts = 0;
do {
try {
currentSetSignatureAttempts++;
Logger.log('currentSetSignatureAttempts: ' + currentSetSignatureAttempts);
var setSignatureResponse = UrlFetchApp.fetch(url, requestBody);
Logger.log('setSignatureResponse on successful attempt:' + setSignatureResponse);
signatureSetSuccessfully = true;
break;
} catch(e) {
Logger.log('set signature failed attempt, waiting 3 seconds and re-trying');
Utilities.sleep(3000);
}
if (currentSetSignatureAttempts >= maxSetSignatureAttempts) {
Logger.log('exceeded ' + maxSetSignatureAttempts + ' set signature attempts, deleting user and ending script');
throw new Error('Something went wrong when setting their email signature.');
}
} while (!signatureSetSuccessfully);
return signatureSetSuccessfully;
}
function getDomainWideDelegationService(serviceName, scope, email) {
Logger.log('starting getDomainWideDelegationService for email: ' + email);
return OAuth2.createService(serviceName + email)
// Set the endpoint URL.
.setTokenUrl(credentials.token_uri)
// Set the private key and issuer.
.setPrivateKey(credentials.private_key)
.setIssuer(credentials.client_email)
// Set the name of the user to impersonate. This will only work for
// Google Apps for Work/EDU accounts whose admin has setup domain-wide
// delegation:
// https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
.setSubject(email)
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scope. This must match one of the scopes configured during the
// setup of domain-wide delegation.
.setScope(scope);
}
It works as I have loginEmail and sendAsEmail set to the loginEmail, but not when set to the one for the domain alias.
I'd appreciate any ideas/help.
Thanks.

REST request to update GMAIL signature with Domain validation

I've created the below code with some help to access any user's signature on my domain in order to standardize the signature across users. Currently, When I specify method 'PATCH' in the URLFetch parameters, All I get is the sendAs resource of the email I sent, including the old signature. If I specify the PUT method, it removes the signature, but will not set the signature I specified onto the account. Could someone help me see what I am doing wrong?
////////////////////////////////////////////////////FUNCTION SET SIGNATURE////////////////////////////////////////////////////////////////////////
/**
* Authorizes and makes a request to the GMail API.
*/
function setSignature(user)
{
var user = 'me#mydomain.com';
var newSig = '<b>This is my new Signature!</b>';
var service = getService(user);
if (service.hasAccess()) {
var url = 'https://www.googleapis.com/gmail/v1/users/'+user+'/settings/sendAs/'+user;
var payload =
{
"sendAsEmail" : user,
"displayName" : AdminDirectory.Users.get(user).name.fullName,
"type" : "patch",
"replyToAddress" : user,
"signature": newSig
};
var options =
{
"method" : "PUT",
"payload" : payload,
"muteHttpExceptions": true,
"contentType": "ctAPPLICATION_JSON",
"headers": {Authorization: 'Bearer ' + service.getAccessToken()}
};
var response = UrlFetchApp.fetch(url, options);
Logger.log(response.getContentText());
} else {
Logger.log(service.getLastError());
}
}
////////////////////////////////////////////////////FUNCTION VIEW SIGNATURE////////////////////////////////////////////////////////////////////////
function viewSignature(user) { var user = USER_EMAIL;
var service = getService(user);
Logger.log(service.hasAccess());
if (service.hasAccess()) {
var url = 'https://www.googleapis.com/gmail/v1/users/'+user+'/settings/sendAs';
var response = UrlFetchApp.fetch(url, {
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
}
});
var result = JSON.parse(response.getContentText());
Logger.log(JSON.stringify(result, null, 2));
} else {
Logger.log(service.getLastError());
}
}
////////////////////////////////////////////////////FUNCTION RESET//////////////////////////////////////////////////////////////////////////////////////
/**
* Reset the authorization state, so that it can be re-tested.
*/
function reset() {
var service = getService();
service.reset();
}
///////////////////////////////////////////////////////////FUNCTION GET SERVICE////////////////////////////////////////////////////////////////////////
/**
* Configures the service.
*/
function getService(user) {
return OAuth2.createService('Gmail:' + user)
// Set the endpoint URL.
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the private key and issuer.
.setPrivateKey(PRIVATE_KEY)
.setIssuer(CLIENT_EMAIL)
// Set the name of the user to impersonate. This will only work for
// Google Apps for Work/EDU accounts whose admin has setup domain-wide
// delegation:
// https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
.setSubject(user)
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scope. This must match one of the scopes configured during the
// setup of domain-wide delegation.
.setScope('https://www.googleapis.com/auth/gmail.settings.basic', 'https://www.googleapis.com/auth/gmail.settings.sharing');
}
////////////////////////////////////////////////////FUNCTION CLEAR SIGNATURE////////////////////////////////////////////////////////////////////////
function clearService(){
OAuth2.createService('drive')
.setPropertyStore(PropertiesService.getUserProperties())
.reset();
}
NOTE: OAuth2 Credentials are stored in Constant variables in a separate file, but I have verified that the credentials return valid data.
Thanks,
My apps works, problem is contentType.
Try:
var formData = {'sendAsEmail':user,'type':'patch','signature': newSig}
var options =
{
'method' : 'put',
'muteHttpExceptions': true,
'contentType': 'application/json',
'headers': {Authorization: 'Bearer ' + service.getAccessToken()},
'payload': JSON.stringify(formData)
};

Making POST Requests in Backbone.js

I have a RESTful server, which accepts url encoded parameters.
In my case, making a post request to https:// my server:8443/test/auth
Set the request header as
Content-Type : application/x-www-form-urlencoded
and passing the parameters
username=myusername
password=mypassword
works and gives the desired response.
I want to achieve the same using Backbonejs. So, I have
Person = Backbone.Model.extend({
initialize: function() {
this.on('all', function(e) { console.log(this.get('name') + " event " + e );
});
},
urlRoot: "https:// my server:8443/test/authauth",
url : function(){
var base = this.urlRoot;
return base + ""
}
});
var person = new Person({ "username" : "myusername" , "password":"mypassword" });
person.save(null, {
beforeSend: function(xhr) {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}}
);
But, it says that no username and password attributes are not present. Waht is the correct way to pass the paramteres in url encoded form in Backbone.js
Thanks