This repository has been archived by the owner on Jan 24, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathopenid.go
96 lines (78 loc) · 3.18 KB
/
openid.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
package auth
import (
"errors"
"fmt"
"net/http"
"net/url"
)
const (
GoogleOpenIdEndpoint = "https://accounts.google.com/o/openid2/auth"
)
var (
ErrAuthDeclined = errors.New("Login was unsuccessful or cancelled by User")
)
var openIdParams = map[string]string{
"openid.ns": "http://specs.openid.net/auth/2.0",
"openid.ns.ax": "http://openid.net/srv/ax/1.0",
"openid.mode": "checkid_setup",
"openid.ax.mode": "fetch_request",
"openid.ax.required": "firstname,lastname,username,language,email",
"openid.ax.type.username": "http://axschema.org/namePerson/friendly",
"openid.ax.type.language": "http://axschema.org/pref/language",
"openid.ax.type.fullname": "http://axschema.org/namePerson",
"openid.ax.type.lastname": "http://axschema.org/namePerson/last",
"openid.ax.type.firstname": "http://axschema.org/namePerson/first",
"openid.ax.type.email": "http://axschema.org/contact/email",
"openid.claimed_id": "http://specs.openid.net/auth/2.0/identifier_select",
"openid.identity": "http://specs.openid.net/auth/2.0/identifier_select",
}
// Base implementation of OpenID for user authentication.
type OpenIdProvider struct {
endpoint string
}
// NewOpenIdProvider allocates and returns a new OpenIdProvider.
func NewOpenIdProvider(endpoint string) *OpenIdProvider {
return &OpenIdProvider{ endpoint }
}
func (self *OpenIdProvider) RedirectRequired(r *http.Request) bool {
return r.URL.Query().Get("openid.mode") == ""
}
// Redirect will send the user to the OpenId Authentication URL
func (self *OpenIdProvider) Redirect(w http.ResponseWriter, r *http.Request) {
// create the url params
var params = make(url.Values)
// construct the Redirect URL with default OpenId params
for key, val := range openIdParams {
params.Add(key, val)
}
// append the real and return_to parameters
// they will be defaulted to the current Host / Path
// TODO use url.New().String() instead string joins below
params.Add("openid.realm", "http://"+r.Host)
params.Add("openid.return_to", "http://"+r.Host+r.URL.Path)
// create the redirect url
redirectTo, _ := url.Parse(self.endpoint)
redirectTo.RawQuery = params.Encode()
// redirect to login
http.Redirect(w, r, redirectTo.String(), http.StatusSeeOther)
}
// GetAuthenticatedUser will retrieve the User information from the URL
// query parameters, per the OpenID specification. If the authentication failed,
// the function will return an error.
func (self *OpenIdProvider) GetAuthenticatedUser(w http.ResponseWriter, r *http.Request) (User, Token, error) {
// Parse the url parameters
params := r.URL.Query()
// Check to see if the user successfully authenticated
if params.Get("openid.mode") == "cancel" {
return nil, nil, ErrAuthDeclined
}
// Get the user details from the URL parameters
lastName := params.Get("openid.ext1.value.lastname")
firstName := params.Get("openid.ext1.value.firstname")
fullName := fmt.Sprintf("%s %s", firstName, lastName)
email := params.Get("openid.ext1.value.email")
// Return the User data
// TODO for now we are re-using the Google User
user := user{id: email, email: email, name: fullName, provider: self.endpoint }
return &user, nil, nil
}