replace zxq.co/ripple/hanayo
This commit is contained in:
273
vendor/github.com/RangelReale/osin/example/openidconnect/openidconnect.go
generated
vendored
Normal file
273
vendor/github.com/RangelReale/osin/example/openidconnect/openidconnect.go
generated
vendored
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
An example of adding OpenID Connect support to osin.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/RangelReale/osin"
|
||||
"github.com/RangelReale/osin/example"
|
||||
|
||||
"gopkg.in/square/go-jose.v1"
|
||||
)
|
||||
|
||||
var (
|
||||
issuer = "http://127.0.0.1:14001"
|
||||
server = osin.NewServer(osin.NewServerConfig(), example.NewTestStorage())
|
||||
|
||||
jwtSigner jose.Signer
|
||||
publicKeys *jose.JsonWebKeySet
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Load signing key.
|
||||
block, _ := pem.Decode(privateKeyBytes)
|
||||
if block == nil {
|
||||
log.Fatalf("no private key found")
|
||||
}
|
||||
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to parse key: %v", err)
|
||||
}
|
||||
|
||||
// Configure jwtSigner and public keys.
|
||||
privateKey := &jose.JsonWebKey{
|
||||
Key: key,
|
||||
Algorithm: "RS256",
|
||||
Use: "sig",
|
||||
KeyID: "1", // KeyID should use the key thumbprint.
|
||||
}
|
||||
|
||||
jwtSigner, err = jose.NewSigner(jose.RS256, privateKey)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to create jwtSigner: %v", err)
|
||||
}
|
||||
publicKeys = &jose.JsonWebKeySet{
|
||||
Keys: []jose.JsonWebKey{
|
||||
jose.JsonWebKey{Key: &key.PublicKey,
|
||||
Algorithm: "RS256",
|
||||
Use: "sig",
|
||||
KeyID: "1",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Register the four manditory OpenID Connect endpoints: discovery, public keys, auth, and token.
|
||||
http.HandleFunc("/.well-known/openid-configuration", handleDiscovery)
|
||||
http.HandleFunc("/publickeys", handlePublicKeys)
|
||||
http.HandleFunc("/authorize", handleAuthorization)
|
||||
http.HandleFunc("/token", handleToken)
|
||||
|
||||
log.Fatal(http.ListenAndServe("127.0.0.1:14001", nil))
|
||||
}
|
||||
|
||||
// The ID Token represents a JWT passed to the client as part of the token response.
|
||||
//
|
||||
// https://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
type IDToken struct {
|
||||
Issuer string `json:"iss"`
|
||||
UserID string `json:"sub"`
|
||||
ClientID string `json:"aud"`
|
||||
Expiration int64 `json:"exp"`
|
||||
IssuedAt int64 `json:"iat"`
|
||||
|
||||
Nonce string `json:"nonce,omitempty"` // Non-manditory fields MUST be "omitempty"
|
||||
|
||||
// Custom claims supported by this server.
|
||||
//
|
||||
// See: https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
|
||||
|
||||
Email string `json:"email,omitempty"`
|
||||
EmailVerified *bool `json:"email_verified,omitempty"`
|
||||
|
||||
Name string `json:"name,omitempty"`
|
||||
FamilyName string `json:"family_name,omitempty"`
|
||||
GivenName string `json:"given_name,omitempty"`
|
||||
Locale string `json:"locale,omitempty"`
|
||||
}
|
||||
|
||||
// handleDiscovery returns the OpenID Connect discovery object, allowing clients
|
||||
// to discover OAuth2 resources.
|
||||
func handleDiscovery(w http.ResponseWriter, r *http.Request) {
|
||||
// For other example see: https://accounts.google.com/.well-known/openid-configuration
|
||||
data := map[string]interface{}{
|
||||
"issuer": issuer,
|
||||
"authorization_endpoint": issuer + "/authorize",
|
||||
"token_endpoint": issuer + "/token",
|
||||
"jwks_uri": issuer + "/publickeys",
|
||||
"response_types_supported": []string{"code"},
|
||||
"subject_types_supported": []string{"public"},
|
||||
"id_token_signing_alg_values_supported": []string{"RS256"},
|
||||
"scopes_supported": []string{"openid", "email", "profile"},
|
||||
"token_endpoint_auth_methods_supported": []string{"client_secret_basic"},
|
||||
"claims_supported": []string{
|
||||
"aud", "email", "email_verified", "exp",
|
||||
"family_name", "given_name", "iat", "iss",
|
||||
"locale", "name", "sub",
|
||||
},
|
||||
}
|
||||
|
||||
raw, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
log.Printf("failed to marshal data: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(raw)))
|
||||
w.Write(raw)
|
||||
}
|
||||
|
||||
// handlePublicKeys publishes the public part of this server's signing keys.
|
||||
// This allows clients to verify the signature of ID Tokens.
|
||||
func handlePublicKeys(w http.ResponseWriter, r *http.Request) {
|
||||
raw, err := json.MarshalIndent(publicKeys, "", " ")
|
||||
if err != nil {
|
||||
log.Printf("failed to marshal data: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(raw)))
|
||||
w.Write(raw)
|
||||
}
|
||||
|
||||
func handleAuthorization(w http.ResponseWriter, r *http.Request) {
|
||||
resp := server.NewResponse()
|
||||
defer resp.Close()
|
||||
|
||||
if ar := server.HandleAuthorizeRequest(resp, r); ar != nil {
|
||||
if !example.HandleLoginPage(ar, w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
ar.Authorized = true
|
||||
scopes := make(map[string]bool)
|
||||
for _, s := range strings.Fields(ar.Scope) {
|
||||
scopes[s] = true
|
||||
}
|
||||
|
||||
// If the "openid" connect scope is specified, attach an ID Token to the
|
||||
// authorization response.
|
||||
//
|
||||
// The ID Token will be serialized and signed during the code for token exchange.
|
||||
if scopes["openid"] {
|
||||
|
||||
// These values would be tied to the end user authorizing the client.
|
||||
now := time.Now()
|
||||
idToken := IDToken{
|
||||
Issuer: issuer,
|
||||
UserID: "id-of-test-user",
|
||||
ClientID: ar.Client.GetId(),
|
||||
Expiration: now.Add(time.Hour).Unix(),
|
||||
IssuedAt: now.Unix(),
|
||||
Nonce: r.URL.Query().Get("nonce"),
|
||||
}
|
||||
|
||||
if scopes["profile"] {
|
||||
idToken.Name = "Jane Doe"
|
||||
idToken.GivenName = "Jane"
|
||||
idToken.FamilyName = "Doe"
|
||||
idToken.Locale = "us"
|
||||
}
|
||||
|
||||
if scopes["email"] {
|
||||
t := true
|
||||
idToken.Email = "jane.doe@example.com"
|
||||
idToken.EmailVerified = &t
|
||||
}
|
||||
// NOTE: The storage must be able to encode and decode this object.
|
||||
ar.UserData = &idToken
|
||||
}
|
||||
server.FinishAuthorizeRequest(resp, r, ar)
|
||||
}
|
||||
|
||||
if resp.IsError && resp.InternalError != nil {
|
||||
log.Printf("internal error: %v", resp.InternalError)
|
||||
}
|
||||
osin.OutputJSON(resp, w, r)
|
||||
}
|
||||
|
||||
func handleToken(w http.ResponseWriter, r *http.Request) {
|
||||
resp := server.NewResponse()
|
||||
defer resp.Close()
|
||||
|
||||
if ar := server.HandleAccessRequest(resp, r); ar != nil {
|
||||
ar.Authorized = true
|
||||
server.FinishAccessRequest(resp, r, ar)
|
||||
|
||||
// If an ID Token was encoded as the UserData, serialize and sign it.
|
||||
if idToken, ok := ar.UserData.(*IDToken); ok && idToken != nil {
|
||||
encodeIDToken(resp, idToken, jwtSigner)
|
||||
}
|
||||
}
|
||||
if resp.IsError && resp.InternalError != nil {
|
||||
fmt.Printf("ERROR: %s\n", resp.InternalError)
|
||||
}
|
||||
osin.OutputJSON(resp, w, r)
|
||||
}
|
||||
|
||||
// encodeIDToken serializes and signs an ID Token then adds a field to the token response.
|
||||
func encodeIDToken(resp *osin.Response, idToken *IDToken, singer jose.Signer) {
|
||||
resp.InternalError = func() error {
|
||||
payload, err := json.Marshal(idToken)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal token: %v", err)
|
||||
}
|
||||
jws, err := jwtSigner.Sign(payload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to sign token: %v", err)
|
||||
}
|
||||
raw, err := jws.CompactSerialize()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to serialize token: %v", err)
|
||||
}
|
||||
resp.Output["id_token"] = raw
|
||||
return nil
|
||||
}()
|
||||
|
||||
// Record errors as internal server errors.
|
||||
if resp.InternalError != nil {
|
||||
resp.IsError = true
|
||||
resp.ErrorId = osin.E_SERVER_ERROR
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
privateKeyBytes = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA4f5wg5l2hKsTeNem/V41fGnJm6gOdrj8ym3rFkEU/wT8RDtn
|
||||
SgFEZOQpHEgQ7JL38xUfU0Y3g6aYw9QT0hJ7mCpz9Er5qLaMXJwZxzHzAahlfA0i
|
||||
cqabvJOMvQtzD6uQv6wPEyZtDTWiQi9AXwBpHssPnpYGIn20ZZuNlX2BrClciHhC
|
||||
PUIIZOQn/MmqTD31jSyjoQoV7MhhMTATKJx2XrHhR+1DcKJzQBSTAGnpYVaqpsAR
|
||||
ap+nwRipr3nUTuxyGohBTSmjJ2usSeQXHI3bODIRe1AuTyHceAbewn8b462yEWKA
|
||||
Rdpd9AjQW5SIVPfdsz5B6GlYQ5LdYKtznTuy7wIDAQABAoIBAQCwia1k7+2oZ2d3
|
||||
n6agCAbqIE1QXfCmh41ZqJHbOY3oRQG3X1wpcGH4Gk+O+zDVTV2JszdcOt7E5dAy
|
||||
MaomETAhRxB7hlIOnEN7WKm+dGNrKRvV0wDU5ReFMRHg31/Lnu8c+5BvGjZX+ky9
|
||||
POIhFFYJqwCRlopGSUIxmVj5rSgtzk3iWOQXr+ah1bjEXvlxDOWkHN6YfpV5ThdE
|
||||
KdBIPGEVqa63r9n2h+qazKrtiRqJqGnOrHzOECYbRFYhexsNFz7YT02xdfSHn7gM
|
||||
IvabDDP/Qp0PjE1jdouiMaFHYnLBbgvlnZW9yuVf/rpXTUq/njxIXMmvmEyyvSDn
|
||||
FcFikB8pAoGBAPF77hK4m3/rdGT7X8a/gwvZ2R121aBcdPwEaUhvj/36dx596zvY
|
||||
mEOjrWfZhF083/nYWE2kVquj2wjs+otCLfifEEgXcVPTnEOPO9Zg3uNSL0nNQghj
|
||||
FuD3iGLTUBCtM66oTe0jLSslHe8gLGEQqyMzHOzYxNqibxcOZIe8Qt0NAoGBAO+U
|
||||
I5+XWjWEgDmvyC3TrOSf/KCGjtu0TSv30ipv27bDLMrpvPmD/5lpptTFwcxvVhCs
|
||||
2b+chCjlghFSWFbBULBrfci2FtliClOVMYrlNBdUSJhf3aYSG2Doe6Bgt1n2CpNn
|
||||
/iu37Y3NfemZBJA7hNl4dYe+f+uzM87cdQ214+jrAoGAXA0XxX8ll2+ToOLJsaNT
|
||||
OvNB9h9Uc5qK5X5w+7G7O998BN2PC/MWp8H+2fVqpXgNENpNXttkRm1hk1dych86
|
||||
EunfdPuqsX+as44oCyJGFHVBnWpm33eWQw9YqANRI+pCJzP08I5WK3osnPiwshd+
|
||||
hR54yjgfYhBFNI7B95PmEQkCgYBzFSz7h1+s34Ycr8SvxsOBWxymG5zaCsUbPsL0
|
||||
4aCgLScCHb9J+E86aVbbVFdglYa5Id7DPTL61ixhl7WZjujspeXZGSbmq0Kcnckb
|
||||
mDgqkLECiOJW2NHP/j0McAkDLL4tysF8TLDO8gvuvzNC+WQ6drO2ThrypLVZQ+ry
|
||||
eBIPmwKBgEZxhqa0gVvHQG/7Od69KWj4eJP28kq13RhKay8JOoN0vPmspXJo1HY3
|
||||
CKuHRG+AP579dncdUnOMvfXOtkdM4vk0+hWASBQzM9xzVcztCa+koAugjVaLS9A+
|
||||
9uQoqEeVNTckxx0S2bYevRy7hGQmUJTyQm3j1zEUR5jpdbL83Fbq
|
||||
-----END RSA PRIVATE KEY-----`)
|
||||
)
|
Reference in New Issue
Block a user