Skip to content
Snippets Groups Projects
main.go 19.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • Nicolas PERNOUD's avatar
    Nicolas PERNOUD committed
    package main
    
    import (
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    	"encoding/json"
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    	"encoding/base64"
    
    Nicolas PERNOUD's avatar
    Nicolas PERNOUD committed
    	"flag"
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    	"io/ioutil"
    
    Nicolas PERNOUD's avatar
    Nicolas PERNOUD committed
    	"net/http"
    
    	"net/url"
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    	"reflect"
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    	"os"
    
    Nicolas PERNOUD's avatar
    Nicolas PERNOUD committed
    	"strconv"
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    	"strings"
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    	log "github.com/sirupsen/logrus"
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    	httpPort    		= flag.Int("http_port", LookupEnvOrInt("HTTP_PORT", 80), "HTTP port to serve on (defaults to 80)")
    	logLevel    		= flag.String("loglevel", LookupEnvOrString("LOGLEVEL", "debug"), "log level (debug, info, warning, error) (defaults to debug)")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    	cozyDomain 			= flag.String("cozy_domain", LookupEnvOrString("COZY_DOMAIN", "cozy.self-data.alpha.grandlyon.com"), "Cozy domain (defaults to cozy.self-data.alpha.grandlyon.com)")
    
    	cozyRedirectURI 	= flag.String("cozy_redirect_uri", LookupEnvOrString("COZY_REDIRECT_URI", "/accounts/enedisgrandlyon/redirect"), "Cozy redirect URI (defaults to /accounts/enedisgrandlyon/redirect)")
    
    	cozyGrdfRedirectURI	= flag.String("cozy_grdf_redirect_uri", LookupEnvOrString("COZY_GRDF_REDIRECT_URI", "/accounts/grdfgrandlyon/redirect"), "Cozy redirect URI (defaults to /accounts/grdfgrandlyon/redirect)")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    	cozyProxyURI		= flag.String("cozy_proxy_uri", LookupEnvOrString("COZY_PROXY_URI", "https://oauth-proxy.self-data.alpha.grandlyon.com"), "Cozy domain (defaults to https://oauth-proxy.self-data.alpha.grandlyon.com)")
    
    type EnedisTokenResponse struct {
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    	AccessToken          string `json:"access_token"`
    	TokenType            string `json:"token_type"`
    	ExpiresIn            int    `json:"expires_in"`
    	RefreshToken         string `json:"refresh_token"`
    	Scope                string `json:"scope"`
    	RefreshTokenIssuedAt string `json:"refresh_token_issued_at"`
    	IssueAt              string `json:"issued_at"`
    	UsagePointId         string `json:"usage_points_id"`
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    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 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    	AccessToken         string `json:"access_token"`
    
    	RefreshToken        string `json:"refresh_token"`
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    	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 {
    	if val, ok := os.LookupEnv(key); ok {
    		return val
    	}
    	return defaultVal
    }
    
    func LookupEnvOrInt(key string, defaultVal int) int {
    	if val, ok := os.LookupEnv(key); ok {
    		v, err := strconv.Atoi(val)
    		if err != nil {
    			log.Fatalf("LookupEnvOrInt[%s]: %v", key, err)
    		}
    		return v
    	}
    	return defaultVal
    }
    
    
    func findItem(arrayType interface{}, item interface{}) bool {
    	arr := reflect.ValueOf(arrayType)
    	if arr.Kind() != reflect.Array {
    		panic("Invalid data-type")
    	}
    	for i := 0; i < arr.Len(); i++ {
    		if arr.Index(i).Interface() == item {
    			return true
    		}
    	}
    
    	return false
    }
    
    
    Nicolas PERNOUD's avatar
    Nicolas PERNOUD committed
    func main() {
    	// Parse the flags
    	flag.Parse()
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    
    	// Init logging
    	log.SetOutput(os.Stdout)
    	log.SetFormatter(&log.TextFormatter{
    		PadLevelText:     true,
    		ForceQuote:       true,
    		DisableTimestamp: false,
    		FullTimestamp:    true,
    		TimestampFormat:  "2006-01-02 15:04:05",
    	})
    
    
    	// Configure log level
    	switch strings.ToLower(*logLevel) {
    	case "error":
    		log.SetLevel(log.ErrorLevel)
    	case "warning":
    		log.SetLevel(log.WarnLevel)
    	case "info":
    		log.SetLevel(log.InfoLevel)
    	case "debug":
    		log.SetLevel(log.DebugLevel)
    	default:
    		log.SetLevel(log.DebugLevel)
    		log.Fatalf("Unknown logging level %s. Choose between debug, info, warning or error.", *logLevel)
    	}
    
    Nicolas PERNOUD's avatar
    Nicolas PERNOUD committed
    	mux := http.NewServeMux()
    
    	log.Infof("Starting Server on port %d\n", *httpPort)
    
    	mux.HandleFunc("/healthcheck", func(w http.ResponseWriter, r *http.Request) {
    		io.WriteString(w, "OK\n")
    	})
    
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    	// ENEDIS AUTH ENDPOINT
    
    	mux.HandleFunc("/auth", func(w http.ResponseWriter, r *http.Request) {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		log.Debug("Enedis - auth - Received new auth request from Cozy")
    
    		query := r.URL.Query()
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		log.Debug("Enedis - auth - query received from Cozy - ", query)
    
    
    		clientId := query.Get("client_id")
    		state := query.Get("state")
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    		responseType := "code"
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		// here we use the redirect_uri param to transmit our stack url
    		// We keep only the instance name to not reach the 100 max char of redirectUrl
    		cozyOrigin := query.Get("redirect_uri")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		if len(clientId) > 0 && len(state) > 0 && len(cozyOrigin) > 0 { 
    			splitIndexStart := strings.Index(cozyOrigin, ":")
    			splitIndexEnd := strings.Index(cozyOrigin, ".")
    			if splitIndexStart > -1 && splitIndexEnd > -1 {
    				instanceName := cozyOrigin[splitIndexStart+3:splitIndexEnd]
    				// DEV API
    				// authURL := "https://gw.hml.api.enedis.fr/dataconnect/v1/oauth2/authorize"
    				// PROD API
    				authURL := "https://mon-compte-particulier.enedis.fr/dataconnect/v1/oauth2/authorize"
    				redirectUrl := authURL + "?client_id=" + clientId + "&duration=P6M&response_type=" + responseType + "&state=" + state + "-" + instanceName
    
    				log.Debug("Enedis - auth - Redirect user to Enedis - ", redirectUrl)
    				http.Redirect(w, r, redirectUrl, 302)
    			} else {
    				log.Error("ProxyError: Enedis - auth - redirect_uri bad format from Cozy " + cozyOrigin)
    				http.Error(w, http.StatusText(500), 500)
    			}
    		} else {
    			log.Error("CozyError: Enedis - auth - Missing parameters in request")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			http.Error(w, http.StatusText(500), 500)
    
    	// GRDF ADICT AUTHORIZE ENDPOINT
    	mux.HandleFunc("/grdf_authorize", func(w http.ResponseWriter, r *http.Request) {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		log.Debug("GRDF - grdf_authorize - Received new auth request from Cozy")
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    		query := r.URL.Query()
    		log.Debug("Query received - ", query)
    
    		clientId := query.Get("client_id")
    		state := query.Get("state")
    		cozyOrigin := query.Get("redirect_uri")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		if len(clientId) > 0 && len(state) > 0 && len(cozyOrigin) > 0 { 
    			splitIndexStart := strings.Index(cozyOrigin, ":")
    			splitIndexEnd := strings.Index(cozyOrigin, ".")
    			if splitIndexStart > -1 && splitIndexEnd > -1 {
    				instanceName := cozyOrigin[splitIndexStart+3:splitIndexEnd]
    				redirectProxy := *cozyProxyURI + "/redirect-grdf"
    				authURL := "https://sofit-sso-oidc.grdf.fr/openam/oauth2/realms/externeGrdf/authorize"
    	
    				redirectUrl := authURL + "?client_id=" + clientId + "&scope=openid&response_type=code&redirect_uri="+ redirectProxy + "&login_hint=Prénom|Nom||Ecolyo&state=" + state + "-" + instanceName
    	
    				log.Debug("GRDF - grdf_authorize - Redirect user to - ", redirectUrl)
    				http.Redirect(w, r, redirectUrl, 302)
    			} else {
    				log.Error("ProxyError: GRDF - grdf_authorize - redirect_uri bad format " + cozyOrigin)
    				http.Error(w, http.StatusText(500), 500)	
    			}
    		} else {
    			log.Error("ProxyError: GRDF - grdf_authorize - Missing parameters in request")
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    			http.Error(w, http.StatusText(500), 500)
    		}
    	})
    
    	//ENEDIS REDIRECT ENDPOINT
    
    	mux.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		log.Debug("Enedis - redirect - Received redirect answer from Enedis")
    
    		query := r.URL.Query()
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    		log.Debug(query)
    
    
    		code := query.Get("code")
    
    		req_state := query.Get("state")
    
    		statusCodes := [4]string{"400", "403", "500", "503"}
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		if len(code) > 0 && len(req_state) > 0 {
    			if findItem(statusCodes, code) {
    				intCode, err := strconv.Atoi(code)
    				if err != nil {
    					log.Error("ProxyError: Enedis - redirect - string to int convert error for status code: ", err)
    					http.Error(w, http.StatusText(500), 500)
    					return
    				}
    				log.Error("EnedisError: Enedis - redirect - status code error : ", code)
    				http.Error(w, http.StatusText(intCode), intCode)
    				return
    
    			splitIndex := strings.Index(req_state, "-")
    			if splitIndex == -1 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				log.Error("ProxyError: Enedis - redirect - No host found in query")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				http.Error(w, http.StatusText(500), 500)
    				return
    
    			}
    			state := req_state[0:splitIndex]
    			host := req_state[splitIndex+1:]
    			usagePointId := query.Get("usage_point_id")
    			cozyURL := "https://" + host + "." + *cozyDomain + *cozyRedirectURI
    			redir := cozyURL + "?code=" + code + "&state=" + state + "&usage_point_id=" + usagePointId
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			log.Debug("Enedis - redirect - Redirect to  Cozy stack - ", redir)
    
    			http.Redirect(w, r, redir, 302)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		} else {
    			log.Error("ProxyError: Enedis - redirect - Missing parameters in request")
    			http.Error(w, http.StatusText(500), 500)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    	//ENEDIS WRONG REDIRECT ENDPOINT
    	mux.HandleFunc("/redirect/", func(w http.ResponseWriter, r *http.Request) {
    		log.Error("EnedisError: Enedis - redirect - wrong route received from Enedis ")
    		http.Error(w, http.StatusText(500), 500)
    	})
    
    
    	//GRDF REDIRECT ENDPOINT
    	mux.HandleFunc("/redirect-grdf", func(w http.ResponseWriter, r *http.Request) {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		log.Debug("GRDF - redirect-grdf - Received redirect answer from GRDF")
    
    		query := r.URL.Query()
    		log.Debug(query)
    
    		code := query.Get("code")
    		req_state := query.Get("state")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		
    		if len(code) > 0 && len(req_state) > 0 {
    			splitIndex := strings.Index(req_state, "-")
    			if splitIndex == -1 {
    				log.Error("ProxyError: GRDF - redirect-grdf - No host found")
    				http.Error(w, http.StatusText(500), 500)
    				return
    			}
    			state := req_state[0:splitIndex]
    			host := req_state[splitIndex+1:]
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			cozyURL := "https://" + host + "." + *cozyDomain + *cozyGrdfRedirectURI
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			redir := cozyURL + "?code=" + code + "&state=" + state
    			log.Debug("GRDF - redirect - Redirect to  Cozy stack - ", redir)
    			http.Redirect(w, r, redir, 302)
    		} else {
    			log.Error("ProxyError: GRDF - redirect - Missing parameters in request")
    			http.Error(w, http.StatusText(500), 500)
    		}
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    	//ENEDIS TOKEN ENDPOINT
    
    	mux.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		log.Debug("Enedis - token - Received new token request from Cozy")
    
    		query := r.URL.Query()
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    		log.Debug(query)
    
    		clientId := ""
    		clientSecret := ""
    		code := ""
    		grantType := ""
    		refreshToken := ""
    
    		// For request token params are into query parameters
    
    		if len(query) == 0 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			log.Debug("Enedis - token - No params found in url query, trying to catch them from body")
    
    			contents, err := ioutil.ReadAll(r.Body)
    			if err != nil {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				log.Error("ProxyError: Enedis - token - Unable to read the body: ", err)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				http.Error(w, err.Error(), 500)
    				return
    			} 
    
    			params, err := url.ParseQuery(string(contents))
    			if err != nil {
    				log.Error(err)
    				http.Error(w, err.Error(), 500)
    				return
    
    			if val, ok := params["client_id"]; ok {
    				clientId = val[0]
    
    			if val, ok := params["client_secret"]; ok {
    				clientSecret = val[0]
    
    			if val, ok := params["code"]; ok {
    				code = val[0]
    
    			if val, ok := params["grant_type"]; ok {
    				grantType = val[0]
    
    			if val, ok := params["refresh_token"]; ok {
    				refreshToken = val[0]
    
    			// Retrieve params from query
    
    			clientId = query.Get("client_id")
    			clientSecret = query.Get("client_secret")
    			code = query.Get("code")
    			grantType = query.Get("grant_type")
    			refreshToken = query.Get("refresh_token")
    		}
    		// Print out the result
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    		log.WithFields(log.Fields{
    			"client_id":     clientId,
    			"client_secret": clientSecret,
    			"code":          code,
    			"grant_type":    grantType,
    			"refresh_token": refreshToken,
    		}).Debug("result")
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    
    
    		// DEV API
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		// tokenUrl := "https://gw.hml.api.enedis.fr/v1/oauth2/token"
    
    		// PROD API
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		tokenUrl := "https://gw.prd.api.enedis.fr/v1/oauth2/token"
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    
    
    		data := url.Values{}
    		data.Set("client_id", clientId)
    		data.Set("client_secret", clientSecret)
    		data.Set("code", code)
    		data.Set("grant_type", grantType)
    
    		if refreshToken != "" {
    			data.Set("refresh_token", refreshToken)
    			data.Set("grant_type", "refresh_token")
    		}
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		log.Debug("Enedis - token - Send request to Enedis token endpoint: ", tokenUrl)
    
    		response, err := http.PostForm(tokenUrl, data)
    
    		if err != nil {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			log.Error("ProxyError: Enedis - token - Unable to post the request: ", err)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			http.Error(w, http.StatusText(500), 500)
    			return
    		} 
    		log.Debug("Enedis - token - Enedis Endpoint response with status ", response.Status)
    		defer response.Body.Close()
    		if response.StatusCode >= 200 && response.StatusCode <= 299 {
    			// Set Content-Type in response header
    			w.Header().Add("Content-Type", "application/json")
    			// Decode response Body using the defined type "TokenResponse"
    			data := EnedisTokenResponse{}
    			decodeError := json.NewDecoder(response.Body).Decode(&data)
    			if decodeError != nil {
    				log.Error("ProxyError: Enedis - token - Unable to decode data: ", decodeError)
    				http.Error(w, decodeError.Error(), 500)
    				return
    			}
    			// Response with json data
    			jsonError := json.NewEncoder(w).Encode(data)
    			if jsonError != nil {
    				log.Error("ProxyError: Enedis - token - Unable to encode data: ", jsonError)
    				http.Error(w, jsonError.Error(), 500)
    				return
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			log.Info("Enedis - token - Response correctly to Cozy stack")
    		} else {
    			log.Error("EnedisError: Enedis - token - Enedis response with status code: ", response.StatusCode)
    			http.Error(w, http.StatusText(response.StatusCode), response.StatusCode)
    
    	//GRDF TOKEN ENDPOINT
    	mux.HandleFunc("/grdf_token", func(w http.ResponseWriter, r *http.Request) {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		log.Debug("GRDF - grdf_token - Received new token request from Cozy")
    
    		query := r.URL.Query()
    		log.Debug(query)
    
    		clientId := ""
    		clientSecret := ""
    		code := ""
    		grantType := ""
    		scope := ""
    
    		redirectUri := *cozyProxyURI + "/redirect-grdf"
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		pce := ""
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		IdToken := ""
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		// For request token params are into query parameters
    		if len(query) == 0 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			log.Debug("GRDF - grdf_token - No params found in url query \nStack probably asks for a refresh token \nTrying to catch them from body")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			contents, err := ioutil.ReadAll(r.Body)
    			if err != nil {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				log.Error("ProxyError: GRDF - grdf_token - Unable to read the body: ", err)
    
    				http.Error(w, err.Error(), 500)
    				return
    
    			params, err := url.ParseQuery(string(contents))
    			if err != nil {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				log.Error("ProxyError: GRDF - grdf_token - Unable to parse the query: ", err)
    
    				http.Error(w, err.Error(), 500)
    				return
    
    			if val, ok := params["client_id"]; ok {
    				clientId = val[0]
    
    			if val, ok := params["client_secret"]; ok {
    				clientSecret = val[0]
    
    			if val, ok := params["grant_type"]; ok {
    				grantType = val[0]
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			// Retrieve params from query
    			clientId = query.Get("client_id")
    			clientSecret = query.Get("client_secret")
    			code = query.Get("code")
    			grantType = query.Get("grant_type")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		// 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"
    
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		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)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			log.Debug("GRDF - grdf_token - data sent is : ", data)
    			log.Debug("GRDF - grdf_token - Send request to access_token endpoint with authorization_code: ", tokenUrl)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			response, err := http.PostForm(tokenUrl, data)
    			if err != nil {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				log.Error("ProxyError: GRDF - grdf_token - Unable to post the request: ", err)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				http.Error(w, http.StatusText(500), 500)
    				return
    			}
    			log.Debug("GRDF - grdf_token - GRDF 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 {
    					log.Error("ProxyError: GRDF - grdf_token - Unable to decode data: ", err)
    					http.Error(w, decodeError.Error(), 500)
    					return
    				}
    				// Check if IdToken exist
    				// Decode the token and retrieve the pce from it
    				if len(data.IdToken) > 0 {
    					IdToken = data.IdToken
    					s := strings.Split(IdToken, ".")
    					if len(s[1]) > 0 {
    						payload, _ := base64.StdEncoding.DecodeString(s[1])
    						// Check if the payload is well ended
    						if payload[len(payload)-1] != 125 {
    							payload = append(payload, []byte{125}...)
    						}
    						log.Debug(string(payload))
    						// Decode the payload from the token
    						var token GrdfConsentementToken
    						err := json.Unmarshal(payload, &token)
    						if err != nil {
    							log.Error("ProxyError: GRDF - grdf_token - Unable to unmarshal payload from token: ", err)
    							http.Error(w, err.Error(), 500)
    							return
    						}
    						log.Debug("Consentements found : ", token.Consentements)
    						// Decode the consentement information
    						if len(token.Consentements) > 0 {
    							var consentements GrdfConsentement
    							err2 := json.Unmarshal([]byte(token.Consentements), &consentements)
    							if err2 != nil {
    								log.Error("ProxyError: GRDF - grdf_token - Unable to unmarshal consentement information: ", err2)
    								http.Error(w, err2.Error(), 500)
    
    								return
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    							if len(consentements[0].Pce) > 0 {
    								pce = consentements[0].Pce
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				if len(pce) <= 0 {
    					log.Error("ProxyError: GRDF - grdf_token - No PCE found")
    					http.Error(w, http.StatusText(500), 500)
    					return
    				}
    			} else {
    				log.Error("GRDFError: GRDF - grdf_token - GRDF response with status code: ", response.StatusCode)
    				http.Error(w, http.StatusText(response.StatusCode), response.StatusCode)
    				return
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		// 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")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		log.Debug("GRDF - grdf_token - data sent is : ", data2)
    		log.Debug("GRDF - grdf_token - Send request to access_token endpoint with client_credentials: ", tokenUrl)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		response2, err2 := http.PostForm(tokenUrl, data2)
    		if err2 != nil {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			log.Error("ProxyError: GRDF - grdf_token - Unable to post the request: ", err2)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			http.Error(w, http.StatusText(500), 500)
    			return
    		} 
    		log.Debug("GRDF - grdf_token - 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(response2.Body).Decode(&data)
    			if decodeError != nil {
    				log.Error("ProxyError: GRDF - grdf_token - Unable to decode data: ", decodeError)
    				http.Error(w, decodeError.Error(), 500)
    				return
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			if grantType != "refresh_token"{
    				data.RefreshToken = "-"
    				data.Pce = pce
    				data.IdToken = IdToken
    			}
    			
    			jsonError := json.NewEncoder(w).Encode(data)
    			if jsonError != nil {
    				log.Error("ProxyError: GRDF - grdf_token - Unable to encode data: ", jsonError)
    				http.Error(w, jsonError.Error(), 500)
    				return
    			}
    			log.Info("GRDF - grdf_token - Response correctly to Cozy stack")
    		} else {
    			log.Error("GRDFError: GRDF - grdf_token - GRDF response with status code: ", response2.StatusCode)
    			http.Error(w, http.StatusText(response2.StatusCode), response2.StatusCode)
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    	log.Fatal(http.ListenAndServe(":"+strconv.Itoa(*httpPort), mux))
    
    Nicolas PERNOUD's avatar
    Nicolas PERNOUD committed
    }