diff --git a/main.go b/main.go index caf0af7b6d4a13ef1e649d65d6413bd8c8359803..f65edad081fd6f8ace90a6671145f83fd6d5523d 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "encoding/base64" "flag" "io" "io/ioutil" @@ -33,12 +34,36 @@ type EnedisTokenResponse struct { UsagePointId string `json:"usage_points_id"` } +type GrdfConsentement []struct { + Pce string `json:"pce"` + IdAccreditation string `json:"id_accreditation"` +} + +type GrdfConsentementToken struct { + AtHash string `json:"at_hash"` + Sub string `json:"sub"` + AuditTrackingId string `json:"auditTrackingId"` + Iss string `json:"iss"` + TokenName string `json:"tokenName"` + Aud string `json:"aud"` + CHash string `json:"c_hash"` + Acr string `json:"acr"` + Azp string `json:"azp"` + AuthYime int `json:"auth_time"` + Realm string `json:"realm"` + Consentements string `json:"consentements"` + Exp int `json:"exp"` + TokenType string `json:"tokenType"` + Iat int `json:"iat"` +} + type GrdfTokenResponse struct { - AccessToken string `json:"access_token"` - IdToken string `json:"id_token"` - TokenType string `json:"token_type"` - ExpiresIn int `json:"expires_in"` - Scope string `json:"scope"` + AccessToken string `json:"access_token"` + IdToken string `json:"id_token"` + TokenType string `json:"token_type"` + ExpiresIn int `json:"expires_in"` + Scope string `json:"scope"` + Pce string `json:"pce"` } func LookupEnvOrString(key string, defaultVal string) string { @@ -205,7 +230,7 @@ func main() { cozyURL := "https://" + host + "." + *cozyDomain + *cozyRedirectURI redir := cozyURL + "?code=" + code + "&state=" + state + "&usage_point_id=" + usagePointId - log.Debug("Redirect to -", redir) + log.Debug("Redirect to - ", redir) http.Redirect(w, r, redir, 302) } }) @@ -229,7 +254,7 @@ func main() { cozyURL := "https://" + host + "." + *cozyDomain + *cozyGrdfRedirectURI redir := cozyURL + "?code=" + code + "&state=" + state - log.Debug("Redirect to -", redir) + log.Debug("Redirect to -", redir) http.Redirect(w, r, redir, 302) }) @@ -336,7 +361,7 @@ func main() { if err != nil { log.Error(err) } else { - log.Debug("Endpoint response with status", response.Status) + log.Debug("Endpoint response with status ", response.Status) defer response.Body.Close() if response.StatusCode >= 200 && response.StatusCode <= 299 { // Set Content-Type in response header @@ -374,122 +399,177 @@ func main() { grantType := "" scope := "" redirectUri := "https://oauth-proxy.wf.alpha.grandlyon.com/redirect-grdf" + pce := "" - // For request token params are into query parameters + // For request token params are into query parameters + if len(query) == 0 { + log.Warn("No params found in url query \nStack probably asks for a refresh token \nTrying to catch them from body") + contents, err := ioutil.ReadAll(r.Body) + if err != nil { + log.Error(err) + } + pageContent := string(contents) + //Check for client_id + clientIdStartIndex := strings.Index(pageContent, "client_id=") + if clientIdStartIndex == -1 { + log.Error("No client_id found") + http.Error(w, http.StatusText(500), 500) + } + clientIdStartIndex += 10 + clientId = pageContent[clientIdStartIndex : clientIdStartIndex+36] + //Check for client_secret + clientSecretStartIndex := strings.Index(pageContent, "client_secret=") + if clientSecretStartIndex == -1 { + log.Error("No client_secret found") + http.Error(w, http.StatusText(500), 500) + } + clientSecretStartIndex += 14 + clientSecret = pageContent[clientSecretStartIndex : clientSecretStartIndex+36] + //Check for code + codeStartIndex := strings.Index(pageContent, "code=") + if codeStartIndex == -1 { + log.Info("No code found (optional param)") + } else { + codeStartIndex += 5 + code = pageContent[codeStartIndex : codeStartIndex+30] + } + //Check for grant_type + grandTypeStartIndex := strings.Index(pageContent, "grant_type=") + if grandTypeStartIndex == -1 { + log.Error("No grant_type found") + http.Error(w, http.StatusText(500), 500) + } + grandTypeStartIndex += 11 + tempGrandTypeString := pageContent[grandTypeStartIndex:] + grandTypeEndIndex := strings.Index(tempGrandTypeString, "&") + if grandTypeEndIndex == -1 { + log.Error("No closing tag for grant_type found") + http.Error(w, http.StatusText(500), 500) + } + grantType = tempGrandTypeString[0:grandTypeEndIndex] - if len(query) == 0 { - log.Warn("No params found in url query \nStack probably asks for a refresh token \nTrying to catch them from body") - contents, err := ioutil.ReadAll(r.Body) - if err != nil { - log.Error(err) - } - pageContent := string(contents) - //Check for client_id - clientIdStartIndex := strings.Index(pageContent, "client_id=") - if clientIdStartIndex == -1 { - log.Error("No client_id found") - http.Error(w, http.StatusText(500), 500) - } - clientIdStartIndex += 10 - clientId = pageContent[clientIdStartIndex : clientIdStartIndex+36] - //Check for client_secret - clientSecretStartIndex := strings.Index(pageContent, "client_secret=") - if clientSecretStartIndex == -1 { - log.Error("No client_secret found") - http.Error(w, http.StatusText(500), 500) - } - clientSecretStartIndex += 14 - clientSecret = pageContent[clientSecretStartIndex : clientSecretStartIndex+36] - //Check for code - codeStartIndex := strings.Index(pageContent, "code=") - if codeStartIndex == -1 { - log.Info("No code found (optional param)") } else { - codeStartIndex += 5 - code = pageContent[codeStartIndex : codeStartIndex+30] - } - //Check for grant_type - grandTypeStartIndex := strings.Index(pageContent, "grant_type=") - if grandTypeStartIndex == -1 { - log.Error("No grant_type found") - http.Error(w, http.StatusText(500), 500) - } - grandTypeStartIndex += 11 - tempGrandTypeString := pageContent[grandTypeStartIndex:] - grandTypeEndIndex := strings.Index(tempGrandTypeString, "&") - if grandTypeEndIndex == -1 { - log.Error("No closing tag for grant_type found") - http.Error(w, http.StatusText(500), 500) + // Retrieve params from query + clientId = query.Get("client_id") + clientSecret = query.Get("client_secret") + code = query.Get("code") + grantType = query.Get("grant_type") } - grantType = tempGrandTypeString[0:grandTypeEndIndex] - - } else { - // Retrieve params from query - clientId = query.Get("client_id") - clientSecret = query.Get("client_secret") - code = query.Get("code") - grantType = query.Get("grant_type") - scope = query.Get("scope") - redirectUri = "https://oauth-proxy.wf.alpha.grandlyon.com/redirect-grdf" - } - // Print out the result - log.WithFields(log.Fields{ - "client_id": clientId, - "client_secret": clientSecret, - "code": code, - "grant_type": grantType, - "redirect_uri": redirectUri, - "scope": scope, - }).Debug("result") + // Print out the result + log.WithFields(log.Fields{ + "client_id": clientId, + "client_secret": clientSecret, + "code": code, + "grant_type": grantType, + "redirect_uri": redirectUri, + "scope": scope, + }).Debug("result") tokenUrl := "https://sofit-sso-oidc.grdf.fr/openam/oauth2/realms/externeGrdf/access_token" - data := url.Values{} - data.Set("client_id", clientId) - data.Set("client_secret", clientSecret) - data.Set("grant_type", grantType) - data.Set("redirect_uri", redirectUri) - if grantType == "authorization_code" { - log.Info("grantType is authorization code") + if grantType != "refresh_token"{ + // Call GRDF access_token endpoint with code & grant_type = "authorization_code" + data := url.Values{} + data.Set("client_id", clientId) + data.Set("client_secret", clientSecret) + data.Set("grant_type", "authorization_code") + data.Set("redirect_uri", redirectUri) data.Set("code", code) - } else if grantType == "client_credentials" { - log.Info("grantType is client_credentials") - data.Set("scope", scope) + + log.Debug("data sent is : ", data) + log.Debug("Send request to token endpoint: ", tokenUrl) + response, err := http.PostForm(tokenUrl, data) + if err != nil { + log.Error(err) + } else { + log.Debug("Endpoint response with status ", response.Status) + defer response.Body.Close() + if response.StatusCode >= 200 && response.StatusCode <= 299 { + // Decode response Body using the defined type "GrdfTokenResponse" + data := GrdfTokenResponse{} + decodeError := json.NewDecoder(response.Body).Decode(&data) + if decodeError != nil { + http.Error(w, decodeError.Error(), 500) + return + } + // Check if AccessToken exist + // Decode the token and retrieve the pce from it + if len(data.AccessToken) > 0 { + s := strings.Split(data.AccessToken, ".") + if len(s[1]) > 0 { + sDec, _ := base64.StdEncoding.DecodeString(s[1]) + payload := append(sDec, []byte{125}...) + // Decode the payload from the token + var token GrdfConsentementToken + err := json.Unmarshal(payload, &token) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), 500) + } + // Decode the consentement information + if len(token.Consentements) > 0 { + var consentements GrdfConsentement + err2 := json.Unmarshal([]byte(token.Consentements), &consentements) + if err2 != nil { + log.Error(err2.Error()) + http.Error(w, err2.Error(), 500) + } + if len(consentements[0].Pce) > 0 { + pce = consentements[0].Pce + } + } + } + } + if len(pce) <= 0 { + log.Error("No PCE found") + http.Error(w, http.StatusText(500), 500) + } + } else { + http.Error(w, http.StatusText(response.StatusCode), response.StatusCode) + } + } } - log.Debug("data sent is : ", data) + // Call GRDF access_token endpoint with scope & grant_type = "client_credentials" + data2 := url.Values{} + data2.Set("client_id", clientId) + data2.Set("client_secret", clientSecret) + data2.Set("grant_type", "client_credentials") + data2.Set("redirect_uri", redirectUri) + data2.Set("scope", "adict/v1") + + log.Debug("data sent is : ", data2) log.Debug("Send request to token endpoint: ", tokenUrl) - response, err := http.PostForm(tokenUrl, data) - if err != nil { - log.Error(err) + response2, err2 := http.PostForm(tokenUrl, data2) + if err2 != nil { + log.Error(err2) } else { - log.Debug("Endpoint response with status", response.Status) - defer response.Body.Close() - if response.StatusCode >= 200 && response.StatusCode <= 299 { + log.Debug("Endpoint response with status ", response2.Status) + defer response2.Body.Close() + if response2.StatusCode >= 200 && response2.StatusCode <= 299 { // Set Content-Type in response header w.Header().Add("Content-Type", "application/json") // Decode response Body using the defined type "GrdfTokenResponse" data := GrdfTokenResponse{} - decodeError := json.NewDecoder(response.Body).Decode(&data) + decodeError := json.NewDecoder(response2.Body).Decode(&data) if decodeError != nil { http.Error(w, decodeError.Error(), 500) return } - log.Info("json token data: ", data) - // if data.id_token { - // DECODE JWT - // } - // Response with json data + if grantType != "refresh_token"{ + data.Pce = pce + } + jsonError := json.NewEncoder(w).Encode(data) if jsonError != nil { http.Error(w, jsonError.Error(), 500) return } } else { - http.Error(w, http.StatusText(response.StatusCode), response.StatusCode) + http.Error(w, http.StatusText(response2.StatusCode), response2.StatusCode) } } })