Skip to content

Challenge-based authentication#4141

Merged
sophiajt merged 12 commits intoAzure:masterfrom
sophiajt:challenge
Jul 23, 2019
Merged

Challenge-based authentication#4141
sophiajt merged 12 commits intoAzure:masterfrom
sophiajt:challenge

Conversation

@sophiajt
Copy link
Contributor

@sophiajt sophiajt commented Jul 1, 2019

This adds challenge-based authentication to the default pipeline for keyvault.

@maririos
Copy link
Member

maririos commented Jul 1, 2019

FYI @Azure/adp-keyvault

@sophiajt sophiajt requested a review from schaabs July 1, 2019 22:07
let retryOptions: any = {};
let pipelineOptions: any = {};
const requestPolicyFactories: RequestPolicyFactory[] = [
proxyPolicy(getDefaultProxySettings((pipelineOptions.proxyOptions || {}).proxySettings)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is valid feedback, but here it is:
Could we export something from our core that would abstract all of these policies away? Something optional, but that would help users avoid this level of complexity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly. Though some policies we're using will be specific to key vault. Most of the policies do live in core-http already.

super(nextPolicy, options);
}

private parseWWWAuthenticate(www_authenticate: string): string {
Copy link
Contributor

@sadasant sadasant Jul 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code seems arbitrary. I believe it's not arbitrary at all! I'm guessing it will help to provide examples of the input that is expected in the form of comments. What do you think? Or a link to an external reference, if available.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could comment this, good call. Right now it assumes you know what the WWW-Authenticate string looks like


if (www_authenticate) {
let resource = this.parseWWWAuthenticate(www_authenticate);
let challenge = new AuthenticationChallenge(resource + "/.default")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this ./default string always going to exist here? I'm curious why would the underlying resource not provide this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is part of the protocol for doing the challenge.

// Use a blank to start the challenge
let headers = webResource.headers;
webResource.headers = new HttpHeaders();
webResource.body = "";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this elicit a challenge for every request?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good point. I thought I had fixed it to check for the existing challenge before starting one. Will fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circling back (I had to page back in what I did) - this uses the cached challenge for each request. So it runs:

await this.authenticateRequest(webResource);

If there is a cached challenge, this will set up the headers for us. Next, we send the request. If the request comes back and isn't a redirection, we just return the result (because we've now used the challenge to do the next policy in the chain)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(saw the bug I think you were pointing out. I think I fixed it)

if (this.challenge != challenge) {
this.challenge = challenge;

await this.authenticateRequest(webResource);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want to also clear the cachedToken in this case so we'll re-authenticate.

@sophiajt sophiajt marked this pull request as ready for review July 22, 2019 21:43
@sophiajt sophiajt changed the title DRAFT: Challenge-based authentication Challenge-based authentication Jul 22, 2019
@sophiajt sophiajt requested a review from schaabs July 22, 2019 21:43
let headers = webResource.headers;
if (this.challenge == undefined) {
// Use a blank to start the challenge
webResource.headers = new HttpHeaders();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

webResource.headers = new HttpHeaders(); [](start = 6, length = 40)

This should actually use the headers from the original request. At the very least the Host header is needed to correctly identity the vault (different vaults may have different auth schemes), but it's safe just to use all the headers.

@sophiajt sophiajt merged commit 929a9fd into Azure:master Jul 23, 2019
@sophiajt sophiajt deleted the challenge branch July 23, 2019 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants