forked from canonical/candid
-
Notifications
You must be signed in to change notification settings - Fork 0
/
visitwebpage.go
96 lines (83 loc) · 2.78 KB
/
visitwebpage.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE.client file for details.
package ussologin
import (
"context"
"net/http"
"net/url"
"github.com/go-macaroon-bakery/macaroon-bakery/v3/httpbakery"
"github.com/juju/usso"
"gopkg.in/errgo.v1"
"gopkg.in/httprequest.v1"
)
const interactionMethod = "usso_oauth"
type interactionInfo struct {
URL string `json:"url,omitempty"`
}
// SetInteraction sets the required values for the usso_oauth interaction
// method on an interaction required error.
func SetInteraction(ierr *httpbakery.Error, url string) {
ierr.SetInteraction(interactionMethod, interactionInfo{
URL: url,
})
}
// NewInteractor creates a new httpbakery.Interactor that interacts using
// the usso_oauth protocol.
func NewInteractor(tg TokenGetter) httpbakery.Interactor {
return &interactor{
tg: tg,
}
}
type interactor struct {
tg TokenGetter
}
// Kind implements httpbakery.Interactor.Kind.
func (*interactor) Kind() string {
return interactionMethod
}
// Interact implements httpbakery.Interactor.Interact.
func (i *interactor) Interact(ctx context.Context, client *httpbakery.Client, location string, ierr *httpbakery.Error) (*httpbakery.DischargeToken, error) {
var info interactionInfo
if err := ierr.InteractionMethod(interactionMethod, &info); err != nil {
return nil, errgo.Mask(err, errgo.Is(httpbakery.ErrInteractionMethodNotFound))
}
var resp LoginResponse
if err := i.interact(ctx, &httprequest.Client{Doer: client}, info.URL, &resp); err != nil {
return nil, errgo.Mask(err, errgo.Any)
}
return resp.DischargeToken, nil
}
// LegacyInteract implements httpbakery.LegacyInteractor.LegacyInteract.
func (i *interactor) LegacyInteract(ctx context.Context, client *httpbakery.Client, location string, u *url.URL) error {
return errgo.Mask(i.interact(ctx, &httprequest.Client{Doer: client}, u.String(), nil), errgo.Any)
}
func (i *interactor) interact(ctx context.Context, client *httprequest.Client, url string, resp interface{}) error {
tok, err := i.tg.GetToken(ctx)
if err != nil {
return errgo.NoteMask(err, "cannot get token", errgo.Any)
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return errgo.Notef(err, "cannot create request")
}
base := *req.URL
base.RawQuery = ""
rp := usso.RequestParameters{
HTTPMethod: req.Method,
BaseURL: base.String(),
Params: req.URL.Query(),
SignatureMethod: usso.HMACSHA1{},
}
if err := tok.SignRequest(&rp, req); err != nil {
return errgo.Notef(err, "cannot sign request")
}
if err := client.Do(ctx, req, resp); err != nil {
return errgo.Mask(err)
}
return nil
}
// A LoginResponse is a response from the login endpoint following a
// successful interaction.
type LoginResponse struct {
DischargeToken *httpbakery.DischargeToken `json:"discharge-token"`
}