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

Add option to set success and error pages for when calling AcquireInt… #490

Open
wants to merge 31 commits into
base: main
Choose a base branch
from

Conversation

wayneforrest
Copy link

@wayneforrest wayneforrest commented Jun 12, 2024

Add option to set success and error web pages for when using AcquireTokenInteractive

For example :

 var successPage = []byte(`<!DOCTYPE html>
     <html>
          <body>A Success Page</body>
     </html>`)
     
 var errorPage = []byte(`<!DOCTYPE html>
     <html>
          <body>A Error Page</body>
     </html>`)
     
    
result, err = client.AcquireTokenInteractive(context.TODO(), scopes,
	public.WithSystemBrowserOptions(successPage, errorPage),
)
if err != nil {
	log.Fatalf("Failed to acquire token interactively: %v", err)
}

@wayneforrest
Copy link
Author

wayneforrest commented Jun 12, 2024 via email

@bgavrilMS bgavrilMS requested a review from localden June 14, 2024 13:20
apps/public/public.go Outdated Show resolved Hide resolved
apps/internal/local/server.go Outdated Show resolved Hide resolved
apps/internal/local/server.go Outdated Show resolved Hide resolved
@wayneforrest wayneforrest force-pushed the feature/set-interactive-auth-success-and-error-pages branch from 13b8895 to 20f93ec Compare June 21, 2024 07:48
@wayneforrest wayneforrest requested a review from chlowell June 27, 2024 20:20
go.mod Outdated Show resolved Hide resolved
@localden
Copy link
Collaborator

@bgavrilMS @chlowell @rayluo overall, the PR looks good to me, but to confirm, we're OK with arbitrary byte[] payloads being passed for error and success pages?

@wayneforrest
Copy link
Author

@bgavrilMS @chlowell @rayluo overall, the PR looks good to me, but to confirm, we're OK with arbitrary byte[] payloads being passed for error and success pages?

Are there any more changes that you would like me to add to this PR?

cc @chlowell you still have a change request on this PR. Has this been resolved for you?

@chlowell
Copy link
Collaborator

chlowell commented Aug 5, 2024

There are still a few things to address here:

  1. we need tests
  2. we should copy any []byte from the application to make its content immutable
  3. Server interpolates error details into failPage:
    _, _ = w.Write([]byte(fmt.Sprintf(failPage, headerErr, desc)))

A few options for addressing item 3:

  1. don't interpolate when the application specified an error page
  2. document the formatting, maybe simplify by interpolating only one string
  3. consider a different design such as taking callbacks returning []byte instead of plain old []byte; then we can pass optional stuff like error details to the application and it can decide whether and how to present them

Option 2 looks good to me; @bgavrilMS @localden @rayluo do you have a preference?

@localden
Copy link
Collaborator

localden commented Aug 5, 2024

There are still a few things to address here:

  1. we need tests
  2. we should copy any []byte from the application to make its content immutable
  3. Server interpolates error details into failPage:
    _, _ = w.Write([]byte(fmt.Sprintf(failPage, headerErr, desc)))

A few options for addressing item 3:

  1. don't interpolate when the application specified an error page
  2. document the formatting, maybe simplify by interpolating only one string
  3. consider a different design such as taking callbacks returning []byte instead of plain old []byte; then we can pass optional stuff like error details to the application and it can decide whether and how to present them

Option 2 looks good to me; @bgavrilMS @localden @rayluo do you have a preference?

Option 2 sounds reasonable to me - formatting to be documented and interpolation simplified. Thanks for reviewing @chlowell!

@rayluo
Copy link
Contributor

rayluo commented Aug 6, 2024

3. Server interpolates error details into failPage:

_, _ = w.Write([]byte(fmt.Sprintf(failPage, headerErr, desc)))

A few options for addressing item 3: ...

What are those 3 options trying to address? I believe, regardless of whether a default failPage or an application-specified s.optionErrorPage is being used, interpolation shall only accept escaped value (example here).

@chlowell
Copy link
Collaborator

chlowell commented Aug 6, 2024

What are those 3 options trying to address? I believe, regardless of whether a default failPage or an application-specified s.optionErrorPage is being used, interpolation shall only accept escaped value (example here).

I'm not worrying about escaping--maybe I should--but developer confusion and unexpected results. If we (try to) augment an application-provided error page with an error message, we should document that behavior or present the message via some API so developers expect the additional content.

@rayluo
Copy link
Contributor

rayluo commented Aug 6, 2024

What are those 3 options trying to address? I believe, regardless of whether a default failPage or an application-specified s.optionErrorPage is being used, interpolation shall only accept escaped value (example here).

I'm not worrying about escaping--maybe I should--but developer confusion and unexpected results. If we (try to) augment an application-provided error page with an error message, we should document that behavior or present the message via some API so developers expect the additional content.

Great. Now we agree to escape the values that will be rendered on the error page. :-)

"Developer confusion and unexpected results" can be avoided by API documentation such as "the error page is treated as a template and its variable $Foo will be interpolated by blah blah". That is an intuitive concept and easily understandable.

@wayneforrest
Copy link
Author

What are those 3 options trying to address? I believe, regardless of whether a default failPage or an application-specified s.optionErrorPage is being used, interpolation shall only accept escaped value (example here).

I'm not worrying about escaping--maybe I should--but developer confusion and unexpected results. If we (try to) augment an application-provided error page with an error message, we should document that behavior or present the message via some API so developers expect the additional content.

Great. Now we agree to escape the values that will be rendered on the error page. :-)

"Developer confusion and unexpected results" can be avoided by API documentation such as "the error page is treated as a template and its variable $Foo will be interpolated by blah blah". That is an intuitive concept and easily understandable.

Option 1 already solves my "personal" needs, for displaying end user friendly pages, where technical error codes / descriptions are not understood (unless you are a developer, useful for debugging).

Also are the messages multi lingual ? If not then Option 2 might not be an ideal solution for all?

Option 3 would allow for error code interpretation; allowing one to suggest a course of action to end users rather than error messages whose audience is more developer orientated. I am not sure how to control the "escaping" as the control falls away (user application space). Perhaps on the return path to the SDK before the server renders the page, the page can be sanitised using something like bluemonday : https://pkg.go.dev/github.com/microcosm-cc/bluemonday ?

@wayneforrest
Copy link
Author

Hi @chlowell thanks for reviewing. Regarding the outstanding list of work:

1: I have added some tests, can you please review. (it's a bit hard to visualise the changes in GitHub)
2: I have also made a "copy" of success/error pages immutable once supplied to the SDK.
3: Interpolation - not done - I made some comments on this above.

@rayluo
Copy link
Contributor

rayluo commented Aug 7, 2024

Option 1 already solves my "personal" needs, for displaying end user friendly pages, where technical error codes / descriptions are not understood (unless you are a developer, useful for debugging).

... not sure how to control the "escaping" as the control falls away (user application space) ...

I have also made a "copy" of success/error pages immutable once supplied to the SDK.

I'm not sure what the benefit is to make "a copy of success/error pages that is immutable". Is that an attack vector unique to Go?

But to be clear, my "escape/sanitize" suggestion is NOT for the app-provided success/error page. I was referring to the interpolation of error code and error description that already exist and is not fixed by this PR.

Technically, you could bypass the "not sure how to escape" issue, by removing that interpolation (even though it is NOT for app-provided error page). But that would risk a regression in the future. I would suggest we escape the error content properly this time.

@wayneforrest
Copy link
Author

I'm not sure what the benefit is to make "a copy of success/error pages that is immutable". Is that an attack vector unique to Go?

I am not sure what the reasoning behind this is, it was suggested by @chlowell to make the []byte immutable. I also checked how golang passes values, and it's by default "value" / "copies" - What I did makes no sense to me now, it's already passing a copy. I think I should revert what I did, but will wait to hear more.

@chlowell
Copy link
Collaborator

chlowell commented Aug 9, 2024

What you reverted was correct--we should copy all slices provided by an application because slices are reference types. A slice value is a pointer to memory, not the content of that memory. We don't want to share a pointer with the application because the application can modify the data pointed to at any time (for example).

@wayneforrest
Copy link
Author

What you reverted was correct--we should copy all slices provided by an application because slices are reference types. A slice value is a pointer to memory, not the content of that memory. We don't want to share a pointer with the application because the application can modify the data pointed to at any time (for example).

Thanks @chlowell ... And for the example! I can also confirm (dang GPT), I checked my Go PL Book page 51, and this commit on the Go Spec. (a slice has a pointer to a backing array)

@wayneforrest wayneforrest force-pushed the feature/set-interactive-auth-success-and-error-pages branch from 6169f27 to 213b935 Compare August 9, 2024 20:44
apps/internal/local/server_test.go Outdated Show resolved Hide resolved
apps/internal/local/server_test.go Outdated Show resolved Hide resolved
apps/internal/local/server.go Outdated Show resolved Hide resolved
apps/internal/local/server.go Outdated Show resolved Hide resolved
@wayneforrest
Copy link
Author

wayneforrest commented Aug 11, 2024

I have made some more changes, which might not be what's wanted yet?

1: I have used html templates, which is injection safe, and removed the Escape from earlier. https://pkg.go.dev/html/template
2: I have refactored the code as suggested by @chlowell (it makes it allot cleaner when checking lengths of optional pages)
3: I have added tests, to ensure the parsing works for when the template variables might and might not be present.
also removed the redundant nil initialisation of the error and success pages
4: I have altered default fail-page also to be a html template (using .Code and .Err template variables)
5: I have added doc comment to the public facing method WithSystemBrowserOptions - wording needs a review.

wayneforrest and others added 25 commits December 1, 2024 09:18
remove the option error page string interpolation.
This reverts commit 6a36074.
using bytes.Equal, eliminating the cast

Co-authored-by: Charles Lowell <[email protected]>
…plication size, instead revert to using html.EscapeString
@wayneforrest wayneforrest force-pushed the feature/set-interactive-auth-success-and-error-pages branch from 7bc0694 to 5c38a70 Compare November 30, 2024 21:12
@wayneforrest wayneforrest force-pushed the feature/set-interactive-auth-success-and-error-pages branch from 27c44ef to f419d6a Compare December 9, 2024 06:33
Copy link

sonarqubecloud bot commented Dec 9, 2024

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