Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

accessing a Vouch Proxy domain using Google App Script? #432

Closed
tahuk opened this issue Oct 4, 2021 · 17 comments
Closed

accessing a Vouch Proxy domain using Google App Script? #432

tahuk opened this issue Oct 4, 2021 · 17 comments
Labels

Comments

@tahuk
Copy link

tahuk commented Oct 4, 2021

I am trying to programmatically access a vouch domain using Google App Script.

I would normally be able to do something like:

var token = ScriptApp.getOAuthToken();
var header = {"Authorization":"Bearer " + token};

var options = {
"method":"GET",
"headers": header,
"muteHttpExceptions": true
};

var url = 'url'

var response =UrlFetchApp.fetch(url, options);

Logger.log(response.getResponseCode()); //returns 200
Logger.log(response.getContentText()); // returns 'sign in with Google' HTML

Following the oAuth flow, I am trying to understand how I can access the cookie or state in order to progress. I was hoping I might be able to do something like:

  var url = 'https://vouch.oursites.com/login?url=https://private.oursites.com';
  var response = UrlFetchApp.fetch(url, {
    muteHttpExceptions: true,
    followRedirects: false,
    headers: {"Authorization":"Bearer " + ScriptApp.getOAuthToken()}
  });
  var cookie = response.getAllHeaders()['Set-Cookie']; //Get cookie from header 
  response = UrlFetchApp.fetch(url, {
    muteHttpExceptions: true,
    followRedirects: true,
    headers: {
      Cookie: cookie, //send the cookie we got as header
    },
  });
  Logger.log(response.getContentText());

What further do I need to do in order to effectively authenticate using GAS?

@bnfinet bnfinet changed the title How can I access Vouch domain using Google App Script? accessing a Vouch domain using Google App Script? Oct 4, 2021
@bnfinet bnfinet changed the title accessing a Vouch domain using Google App Script? accessing a Vouch Proxy domain using Google App Script? Oct 4, 2021
@bnfinet
Copy link
Member

bnfinet commented Oct 4, 2021

@tahuk I'm not familiar with Google App Scripts.

Could you please clarify your use case and describe in plain terms what you're trying to do? Are you trying to use javascript to access Google Docs? I would love to understand what you're doing.

@tahuk
Copy link
Author

tahuk commented Oct 4, 2021

@bnfinet

Yes, partially. I'd like to use Google App Script (essentially JavaScript) to access a domain protected with Vouch. The use case here is that we have a 3rd party web app I was previously able to access using the API.

https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app

The app in question is Zabbix, API docs link: https://www.zabbix.com/documentation/current/manual/api/reference/user/login

Per the Zabbix docs, I was able to do something like:

function authZabbix() {
	var url = 'URL_to_Zabbix_instance';
	var myBody = {
		"jsonrpc": "2.0",
		"method": "user.login",
		"params": {
			"user": "NON-GOOGLE-USER-NAME",
			"password": "MY_PASSWORD"
		},
		"id": 1,
		"auth": null
	};
	var headers = {
		"Accept": "application/json"
	};
	var params = {
		'method': 'POST',
		'muteHttpExceptions': true,
		'headers': headers,
		'contentType': 'application/json',
		'payload': JSON.stringify(myBody)
	};
	var res = UrlFetchApp.fetch(url, params);
	var myObj = JSON.parse(res.getContentText());
	console.log(myObj)
}

However, now we have moved the web app to a Vouch domain, and when the same request, I am only returned the 'sign in with Google' HTML.

I thought that maybe I could use .getOAuthToken() to authenticate my user and log me in but I was not aware of the Vouch oAuth flow.

I am fairly comfortable in Javascript/Google App Script, but not aware at all of Nginx or the concepts used here.

In my post, I reference how to get and send cookies as a header, so I'm sure it must be possible but what I want to be able to do is some sort of request that effectively logs me in and then allows me to fetch like the Zabbix API example above.

Does that help?

@bnfinet
Copy link
Member

bnfinet commented Oct 6, 2021

@tahuk thanks for sharing a bit more about what's going on

The user information from VP can be passed down to an application (such as Zabbix) via HTTP headers. It's a bit of a hack but by making an fetch request to document.location (the same Zabbix URL) [1] or possibly to https://vouch.oursites.com/validate you could gain access to the headers and then pass the user information from X-Vouch-User to myBody.params.user

@tahuk would that work?

We have talked on occasion about offering a mechanism to access the user's information via a javascript library but we have not approached a design in earnest. The Vouch Proxy JWT is held in a cookie and could be parsed but that would require decompressing the cookie and evaluating the blob including the signature. The JWT may be held in several similarly named cookies due to browser cookie size limitations so this is a bit of an operation.

[1] https://stackoverflow.com/questions/220231/accessing-the-web-pages-http-headers-in-javascript

@tahuk
Copy link
Author

tahuk commented Oct 6, 2021

@bnfinet Thanks. I'm not needing to pass anything to Zabbix in this instance, but do want to get enough to login to Google. Another example would be if I had mydomain.com/file.csv, I want to be able to view file.csv programmatically.

I can't see any x-Vouch-User, but did see both Set-Cookie and x-auto-login. Additionally, note that as part of location I am also able to obtain a state but a don't know if this is useful. Hopefully reviewing the following can assist you in guiding me further in the right direction, thanks!!

This is what I've tried so far:

Have tried both auth in my request header, either:
{"Authorization":"Bearer " + token};, or
{"Authorization": "Basic " + Utilities.base64Encode(USERNAME + ":" + LESS_SECURE_APP_PASSWORD)};

 

Request URL: Zabbix install URL
Auth: Bearer
followRedirects: false

{ Connection: 'keep-alive',
  'Content-Type': 'text/html',
  Server: 'nginx/1.14.0 (Ubuntu)',
  'Content-Length': '170',
  Location: 'https://vouch.oursites.com/login?url=https://ZABBIX-URL/&vouch-failcount=&X-Vouch-Token=&error=',
  Date: 'Wed, 06 Oct 2021 18:14:26 GMT' }

Request URL: Zabbix install URL
Auth: Bearer or Basic
followRedirects: true

{ 'Transfer-Encoding': 'chunked',
  Expires: 'Mon, 01 Jan 1990 00:00:00 GMT',
  'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
  Server: 'GSE',
  'X-Frame-Options': 'DENY',
  'Content-Security-Policy': 'script-src \'report-sample\' \'nonce-2esFFokiW0LvmgvwWvHWHg\' \'unsafe-inline\' \'unsafe-eval\';object-src \'none\';base-uri \'self\';report-uri /cspreport',
  'alt-svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"',
  'Set-Cookie': '__Host-GAPS=1:0fI83........................Y80X3oV1RFmOto;Path=/;Expires=Fri, 06-Oct-2023 18:17:29 GMT;Secure;HttpOnly;Priority=HIGH',
  Pragma: 'no-cache',
  'Content-Encoding': 'gzip',
  'x-auto-login': 'realm=com.google&args=continue%3Dhttps%253A%252F%252Faccounts.google.com%252Fsignin%252Foauth%252Flegacy%252Fconsent%253Fauthuser%253Dunknown%2526part%253D..........................8akh.apps.googleusercontent.com%2523',
  'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
  'Content-Type': 'text/html; charset=UTF-8',
  'X-Content-Type-Options': 'nosniff',
  'X-XSS-Protection': '1; mode=block',
  Date: 'Wed, 06 Oct 2021 18:17:29 GMT' }

Request URL: https://vouch.oursites.com/validate
Auth: Bearer or Basic
followRedirects: false

token contains an invalid number of segments

{ 'X-Content-Type-Options': 'nosniff',
  Connection: 'keep-alive',
  'Content-Length': '45',
  'Content-Type': 'text/plain; charset=utf-8',
  Date: 'Wed, 06 Oct 2021 18:32:40 GMT',
  Server: 'nginx/1.14.0 (Ubuntu)' }

Request URL: https://vouch.oursites.com/validate/login?url=https://ZABBIX-URL/
Auth: Bearer or Basic
followRedirects: false

{ 'Content-Type': 'text/html; charset=utf-8',
  Server: 'nginx/1.14.0 (Ubuntu)',
  Connection: 'keep-alive',
  Location: 'https://accounts.google.com/o/oauth2/auth?client_id=114..........kh.apps.googleusercontent.com&hd=oursites.com&redirect_uri=https%3A%2F%2Fvouch.oursites.com%2Fauth&response_type=code&scope=email&state=pEMPv0.................OkR1k',
  'Set-Cookie': 'VouchSession=MTYzMzU0NDkwM.............qN8Lt2ZMvsiI7FndnjUzFGH3U=; Path=/; Expires=Wed, 06 Oct 2021 18:33:21 GMT; Max-Age=300; HttpOnly',
  'Content-Length': '307',
  Date: 'Wed, 06 Oct 2021 18:28:21 GMT' }

Request URL: https://accounts.google.com/o/oauth2/auth?client_id=114..........kh.apps.googleusercontent.com&hd=oursites.com&redirect_uri=https%3A%2F%2Fvouch.oursites.com%2Fauth&response_type=code&scope=email&state=pEMPv0.................OkR1k
Auth: Bearer or Basic
followRedirects: false

{ 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
  'Content-Type': 'text/html; charset=UTF-8',
  Pragma: 'no-cache',
  'X-XSS-Protection': '1; mode=block',
  Date: 'Wed, 06 Oct 2021 18:37:31 GMT',
  'Content-Security-Policy': 'script-src \'report-sample\' \'nonce-E55aCABNgnnAh/rQSc1+sA\' \'unsafe-inline\' \'unsafe-eval\';object-src \'none\';base-uri \'self\';report-uri /cspreport',
  'Set-Cookie': '__Host-GAPS=1:_vi9hkKz..........o3MWa;Path=/;Expires=Fri, 06-Oct-2023 18:37:31 GMT;Secure;HttpOnly;Priority=HIGH',
  Expires: 'Mon, 01 Jan 1990 00:00:00 GMT',
  'Transfer-Encoding': 'chunked',
  'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
  Server: 'GSE',
  'alt-svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"',
  'x-auto-login': 'realm=com.google&args=continue%3Dhttps%253A%252F%252Faccounts.google.com%252Fsignin%252Foauth%252Flegacy%252Fconsent%253Fauthuser%253Dunknown%2526part%253DAJi8hANHU_........2nbj8akh.apps.googleusercontent.com%2523',
  'X-Content-Type-Options': 'nosniff',
  'Content-Encoding': 'gzip',
  'X-Frame-Options': 'DENY' }

@bnfinet
Copy link
Member

bnfinet commented Oct 6, 2021

just use https://vouch.oursites.com/validate for the time being

try credentials: 'include' as per
https://stackoverflow.com/questions/34558264/fetch-api-with-cookie

Could you please include the response codes, like "200 OK" or "401 Not Authorized" as well, really all info returned by the response header would be helpful.

@tahuk
Copy link
Author

tahuk commented Oct 6, 2021

@bnfinet

Thanks, with credentials: 'include', this what I get.

Request URL: https://vouch.oursites.com/validate
HTTP Code: 401

token contains an invalid number of segments


{ 'Content-Type': 'text/plain; charset=utf-8',
  'Content-Length': '45',
  Server: 'nginx/1.14.0 (Ubuntu)',
  Date: 'Wed, 06 Oct 2021 19:04:24 GMT',
  'X-Content-Type-Options': 'nosniff',
  Connection: 'keep-alive' }

@bnfinet
Copy link
Member

bnfinet commented Oct 6, 2021

@tahuk excellent, now we're getting somewhere.

Try it with document.location as the URL as well please.

My suspicion is that the VP cookies (multiple as per #109) are being sent but are not recombined into a working JWT.

Could you please use developer tools to look at the cookies? You're going to have to ferret out how to proceed and try some things.

Can you please post your fetch code to a repo or gist?

Have you been discussing your issue with your SRE/devops/sysadmin? They may be able to advise you on how to make that request to /validate

@tahuk
Copy link
Author

tahuk commented Oct 6, 2021

@bnfinet The fetch code is just:

function fetch() {
    var token = ScriptApp.getOAuthToken();
    // both of these headers should effectively be the same, one or the other or both should work
    var header = {"Authorization":"Bearer " + token};
    var header = {"Authorization": "Basic " + Utilities.base64Encode('MY_ORG_GMAIL' + ":" + 'MY_LESS_SECURE_APP_PASSWORD')};

    var options = {
        "method":"GET",
        "headers": header,
        "muteHttpExceptions": true,
        "followRedirects": true,
        "credentials": 'include'
    };

    var url = 'URL HERE'

    var response =UrlFetchApp.fetch(url, options);

    console.log(response.getResponseCode());
    console.log(response.getContentText());
    console.log(response.getAllHeaders());
}

Assuming document.location you mean either the subdomain root or Zabbix installation for example - ie the URL the user sees and intends to go to?

In which case I get:

HTTP 200

{ Pragma: 'no-cache',
  'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
  Expires: 'Mon, 01 Jan 1990 00:00:00 GMT',
  Date: 'Wed, 06 Oct 2021 20:18:02 GMT',
  'X-XSS-Protection': '1; mode=block',
  'Content-Type': 'text/html; charset=UTF-8',
  'x-auto-login': 'realm=com.google&args=continue%3Dhttps%253A%252F%252Faccounts.google.com%252Fsignin%252Foauth%252Flegacy%252Fconsent%253Fauthuser%253Dunknown%2526part%253DA......82682166%2526client_id%253D.......08vgl2nbj8akh.apps.googleusercontent.com%2523',
  'Content-Encoding': 'gzip',
  'Content-Security-Policy': 'script-src \'report-sample\' \'nonce-wHSJfcEhw+HaGOXwrvDufA\' \'unsafe-inline\' \'unsafe-eval\';object-src \'none\';base-uri \'self\';report-uri /cspreport',
  'alt-svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"',
  'X-Content-Type-Options': 'nosniff',
  'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
  'Transfer-Encoding': 'chunked',
  'X-Frame-Options': 'DENY',
  Server: 'GSE',
  'Set-Cookie': '__Host-GAPS=1:5MDb.....Rgw:SXPCnjmJhUriEd5R;Path=/;Expires=Fri, 06-Oct-2023 20:18:02 GMT;Secure;HttpOnly;Priority=HIGH' }

Could you please use developer tools to look at the cookies?

I'm not sure how to get dev tools or similar in the google app script code editor, but I can return things like the header as above but can also get blobs, like downloading a pdf or an image and doing stuff with them.

Have you been discussing your issue with your SRE/devops/sysadmin?

I haven't but do intend to, but I'd be surprised if they really knew much more than following your installation guide etc.

@bnfinet
Copy link
Member

bnfinet commented Oct 6, 2021

@bnfinet The fetch code is just:

yes, please put that in a gist or repo so I can link to line numbers and you can revise and update the code instead of cutting and pasting it here a bunch of times.

Assuming document.location you mean either the subdomain root or Zabbix installation for example - ie the URL the user sees and intends to go to?

yes, the URL of the original request as carried in javascript at document.location.

I didn't appreciate that you were using google app script code editor. I assumed you were writing js at zabbix.yourdomain.com or something similar

What domain is this code running at? Is it in yourdomain.com the same domain as vouch.yourdomain.com and zabbix.yourdomain.com`?

Have you been discussing your issue with your SRE/devops/sysadmin?

I haven't but do intend to, but I'd be surprised if they really knew much more than following your installation guide etc.

Could you please ask them to chime into this thread with the Nginx config, etc posted to a gist as per the README.

@bnfinet
Copy link
Member

bnfinet commented Oct 8, 2021

@tahuk there's two problems I see in the fetch code and a few things we could try out as well. As soon as it's in a gist I'll be happy to highlight them :)

@tahuk
Copy link
Author

tahuk commented Oct 8, 2021

@bnfinet
Copy link
Member

bnfinet commented Oct 8, 2021

comment these out https://gist.github.com/tahuk/7ac8c00ed6c83776dbc7fc8a9af8349e#file-authvouch-gs-L9-L10

"credentials": 'include' should offer the VP cookie as part of the fetch request.

If that doesn't work, use document.location as the URL.

@tahuk
Copy link
Author

tahuk commented Oct 8, 2021

To answer previous question. The script is running from a Google server, not on the same domain as the VP.

I am using the var header to login. Removing that returns this header:

{ 'X-XSS-Protection': '1; mode=block',
  'X-Content-Type-Options': 'nosniff',
  'Set-Cookie': '__Host-GAPS=1:jkE.....................qlE;Path=/;Expires=Sun, 08-Oct-2023 21:07:11 GMT;Secure;HttpOnly;Priority=HIGH',
  Pragma: 'no-cache',
  'x-auto-login': 'realm=com.google&args=continue%3Dhttps%253A%252F%252Faccounts.google.com%252Fsignin%252Foauth%252Flegacy%252Fconsent%253Fauthuser%253Dunknown%2526part%25............nbj8akh.apps.googleusercontent.com%2523',
  'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
  'Transfer-Encoding': 'chunked',
  'Content-Type': 'text/html; charset=UTF-8',
  Server: 'GSE',
  'X-Frame-Options': 'DENY',
  'Content-Security-Policy': 'script-src \'report-sample\' \'nonce-oIm8Xy5mkiBIfqQ1j/1ZrA\' \'unsafe-inline\' \'unsafe-eval\';object-src \'none\';base-uri \'self\';report-uri /cspreport',
  'Content-Encoding': 'gzip',
  'alt-svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"',
  Expires: 'Mon, 01 Jan 1990 00:00:00 GMT',
  'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
  Date: 'Fri, 08 Oct 2021 21:07:11 GMT' }

@bnfinet
Copy link
Member

bnfinet commented Oct 8, 2021

Are you saying that your script is running outside of a VP protected domain?

I was assuming that Zabbix was protected by VP and that you were logging into Google via VP and then getting access to Zabbix where your script is running.

But I think I'm hearing that that's not what you're attempting, your trying to access Zabbix which is protected by VP without first logging into Zabbix and from a different domain. Do I have that right?

That's not going to work.

@tahuk
Copy link
Author

tahuk commented Oct 8, 2021

@bnfinet Correct. I am authorising the script as myself, using

https://developers.google.com/apps-script/reference/script/script-app#getOAuthToken()

I would have expected VP to accept this as if the user was typing in their user/pass.

@bnfinet
Copy link
Member

bnfinet commented Oct 8, 2021

@tahuk that's not how VP works

VP forwards a user to the IdP (google). After the user authenticates with the IdP (with username and password or otherwise) the user is forwaded back to VP at which point VP issues its own token. VP does not ever receive the IdP login credentials (username and password).

The VP token is (almost always) carried in a cookie. That cookie is only available within the shared VP protected domain.

I'm going to close this though you're welcome to continue the conversation. There has been some talk of developing other access mechanisms for VP but I can't see Google App Script being the right stating point for that effort.

@bnfinet bnfinet closed this as completed Oct 8, 2021
@Manca
Copy link

Manca commented Aug 13, 2022

Hi @bnfinet -- I'll quickly reopen this one to clarify one thing.

Are you saying that protected domain such as: https://api.domain.com can't be accessed from anywhere else other than the local apps that are running under the same scope/server (such as: https://app.domain.com, https://www.domain.com, etc), basically the ones that share the VouchCookie? So if I wanted to Authenticate/Authorize using the Bearer token when making a curl request to https://api.domain.com, I won't be able to do so?

Basically, the protection is only in the scope of the existing cookie which is created when the user manually logs-in. It's not possible to use Bearer token from either Vouch or IDP to access the protected server/api?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants