123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- package discourse
- import (
- "crypto/hmac"
- "crypto/sha256"
- "encoding/base64"
- "encoding/hex"
- "fmt"
- "net/url"
- "strconv"
- "strings"
- "github.com/google/uuid"
- )
- // SsoConfig - Configuration for an SSO Request
- type SsoConfig struct {
- Endpoint string
- ReturnEndpoint string
- Secret string
- UUID uuid.UUID
- }
- // GetSSORequestURL - gets a url for an sso request
- func GetSSORequestURL(config SsoConfig) string {
- url := generateSSORequestURL(config)
- return url
- }
- // ValidateSsoResponse - Validate the signature on the sso response
- func ValidateSsoResponse(sso, sig, secret string) bool {
- ssoDataSig := computeHmac256(sso, secret)
- return sig == ssoDataSig
- }
- func generateSSORequestURL(config SsoConfig) string {
- // Build the query string payload
- payload := fmt.Sprintf("nonce=%s&return_sso_url=%s", config.UUID, config.ReturnEndpoint)
- // Base64 encode the payload
- base64Payload := base64.StdEncoding.EncodeToString([]byte(payload))
- // Urlencode the
- URLEncodedPayload := url.QueryEscape(base64Payload)
- // Get a hex signature for this payload with the sso secret
- hexSignature := computeHmac256(base64Payload, config.Secret)
- ssoURL := fmt.Sprintf("%s?sso=%s&sig=%s", config.Endpoint, URLEncodedPayload, hexSignature)
- return ssoURL
- }
- // GenerateSSO - Generate the sso and sig for an sso request
- func GenerateSSO(nonce string, returnEndpoint, secret string) (string, string) {
- // Build the query string payload
- payload := fmt.Sprintf("nonce=%s&return_sso_url=%s", nonce, returnEndpoint)
- // Base64 encode the payload
- base64Payload := base64.StdEncoding.EncodeToString([]byte(payload))
- // Urlencode the
- URLEncodedPayload := url.QueryEscape(base64Payload)
- // Get a hex signature for this payload with the sso secret
- hexSignature := computeHmac256(base64Payload, secret)
- return URLEncodedPayload, hexSignature
- }
- // GetSSOUrl - Generate the sso enpodint url give the domain, sso and sig
- func GetSSOUrl(endpoint, sso, sig string) string {
- return fmt.Sprintf("%s/session/sso_provider?sso=%s&sig=%s", endpoint, sso, sig)
- }
- // Create a hex signature from a message and secret
- func computeHmac256(message string, secret string) string {
- key := []byte(secret)
- h := hmac.New(sha256.New, key)
- h.Write([]byte(message))
- return hex.EncodeToString(h.Sum(nil))
- }
- func ParseSSOResponse(ssoData string) (SSOResponse, error) {
- decodedSsoData, err := base64.StdEncoding.DecodeString(ssoData)
- if err != nil {
- return SSOResponse{}, err
- }
- queryData, err := url.ParseQuery(string(decodedSsoData))
- if err != nil {
- return SSOResponse{}, err
- }
- id, _ := strconv.Atoi(queryData.Get("external_id"))
- response := SSOResponse{
- ID: id,
- Admin: (queryData.Get("admin") == "true"),
- Moderator: (queryData.Get("moderator") == "true"),
- Groups: strings.Split(queryData.Get("groups"), ","),
- Username: queryData.Get("username"),
- Nonce: queryData.Get("nonce"),
- }
- return response, nil
- }
|