Skip to content
Snippets Groups Projects
main.go 18.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")
    		splitIndexStart := strings.Index(cozyOrigin, ":")
    		if splitIndexStart == -1 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			log.Error("ProxyError: Enedis - auth - redirect_uri bad format from Cozy" + cozyOrigin)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			http.Error(w, http.StatusText(500), 500)
    		}
    		splitIndexEnd := strings.Index(cozyOrigin, ".")
    		if splitIndexEnd == -1 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			log.Error("ProxyError: Enedis - auth - redirect_uri bad format from Cozy" + cozyOrigin)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			http.Error(w, http.StatusText(500), 500)
    		}
    		instanceName := cozyOrigin[splitIndexStart+3:splitIndexEnd]
    
    		// DEV API
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		// authURL := "https://gw.hml.api.enedis.fr/dataconnect/v1/oauth2/authorize"
    
    		// PROD API
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		authURL := "https://mon-compte-particulier.enedis.fr/dataconnect/v1/oauth2/authorize"
    
    		redirectUrl := authURL + "?client_id=" + clientId + "&duration=P6M&response_type=" + responseType + "&state=" + state + "-" + instanceName
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		log.Debug("Enedis - auth - Redirect user to Enedis - ", redirectUrl)
    
    		http.Redirect(w, r, redirectUrl, 302)
    
    	// 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")
    		splitIndexStart := strings.Index(cozyOrigin, ":")
    		if splitIndexStart == -1 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			log.Error("ProxyError: GRDF - grdf_authorize - redirect_uri bad format " + cozyOrigin)
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    			http.Error(w, http.StatusText(500), 500)
    		}
    		splitIndexEnd := strings.Index(cozyOrigin, ".")
    		if splitIndexEnd == -1 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			log.Error("ProxyError: GRDF - grdf_authorize - redirect_uri bad format " + cozyOrigin)
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    			http.Error(w, http.StatusText(500), 500)
    		}
    		instanceName := cozyOrigin[splitIndexStart+3:splitIndexEnd]
    
    
    		redirectProxy := *cozyProxyURI + "/redirect-grdf"
    
    		authURL := "https://sofit-sso-oidc.grdf.fr/openam/oauth2/realms/externeGrdf/authorize"
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    
    
    		redirectUrl := authURL + "?client_id=" + clientId + "&scope=openid&response_type=code&redirect_uri="+ redirectProxy + "&login_hint=Prénom|Nom||Ecolyo&state=" + state + "-" + instanceName
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		log.Debug("GRDF - grdf_authorize - Redirect user to - ", redirectUrl)
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    		http.Redirect(w, r, redirectUrl, 302)
    	})
    
    	//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"}
    
    		if (findItem(statusCodes, code)) {
    			intCode, err := strconv.Atoi(code)
    			if err != nil {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				log.Error("ProxyError: Enedis - redirect - string to int convert error for status code: ", err)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			log.Error("EnedisError: Enedis - redirect - status code error : ", code)
    
    			http.Error(w, http.StatusText(intCode), intCode)
    		} else {
    			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")
    
    			}
    			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)
    		}
    
    	//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")
    		//TODO Get pce_id
    		splitIndex := strings.Index(req_state, "-")
    		if splitIndex == -1 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			log.Error("ProxyError: GRDF - redirect-grdf - No host found")
    
    		}
    		state := req_state[0:splitIndex]
    		host := req_state[splitIndex+1:]
    
    
    		cozyURL := "https://" + host + "." + *cozyDomain + *cozyGrdfRedirectURI
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    		redir := cozyURL + "?code=" + code + "&state=" + state
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		log.Debug("GRDF - redirect - Redirect to  Cozy stack - ", redir)
    
    		http.Redirect(w, r, redir, 302)
    	})
    
    
    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)
    
    
    			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)
    
    		} else {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			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 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    					log.Error("ProxyError: Enedis - token - Unable to decode data: ", decodeError)
    
    					http.Error(w, decodeError.Error(), 500)
    					return
    				}
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    
    
    				// Response with json data
    				jsonError := json.NewEncoder(w).Encode(data)
    				if jsonError != nil {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    					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")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				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
    			} else {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				log.Debug("GRDF - grdf_token - GRDF Endpoint response with status ", response.Status)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				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 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    						log.Error("ProxyError: GRDF - grdf_token - Unable to decode data: ", err)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    						http.Error(w, decodeError.Error(), 500)
    						return
    					}
    
    					// Check if IdToken exist
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    					// Decode the token and retrieve the pce from it
    
    					if len(data.IdToken) > 0 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    						IdToken = data.IdToken
    						s := strings.Split(IdToken, ".")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    						if len(s[1]) > 0 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    							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))
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    							// Decode the payload from the token
    							var token GrdfConsentementToken
    							err := json.Unmarshal(payload, &token)
    							if err != nil {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    								log.Error("ProxyError: GRDF - grdf_token - Unable to unmarshal payload from token: ", err)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    								http.Error(w, err.Error(), 500)
    
    								return
    
    							log.Debug("Consentements found : ", token.Consentements)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    							// Decode the consentement information
    							if len(token.Consentements) > 0 {
    								var consentements GrdfConsentement
    								err2 := json.Unmarshal([]byte(token.Consentements), &consentements)
    								if err2 != nil {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    									log.Error("ProxyError: GRDF - grdf_token - Unable to unmarshal consentement information: ", err2)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    									http.Error(w, err2.Error(), 500)
    
    									return
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    								}
    								if len(consentements[0].Pce) > 0 {
    									pce = consentements[0].Pce
    								}
    							}
    						}
    					}
    					if len(pce) <= 0 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    						log.Error("ProxyError: GRDF - grdf_token - No PCE found")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    						http.Error(w, http.StatusText(500), 500)
    
    						return
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    					}
    				} else {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    					log.Error("GRDFError: GRDF - grdf_token - GRDF response with status code: ", response.StatusCode)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    					http.Error(w, http.StatusText(response.StatusCode), response.StatusCode)
    				}
    			}
    
    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
    			log.Debug("GRDF - grdf_token - Endpoint response with status ", response2.Status)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			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{}
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				decodeError := json.NewDecoder(response2.Body).Decode(&data)
    
    				if decodeError != nil {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    					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"{
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    					data.RefreshToken = "-"
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    					data.Pce = pce
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    					data.IdToken = IdToken
    
    				jsonError := json.NewEncoder(w).Encode(data)
    				if jsonError != nil {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    					log.Error("ProxyError: GRDF - grdf_token - Unable to encode data: ", jsonError)
    
    					http.Error(w, jsonError.Error(), 500)
    					return
    				}
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				log.Info("GRDF - grdf_token - Response correctly to Cozy stack")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				log.Error("GRDFError: GRDF - grdf_token - GRDF response with status code: ", response2.StatusCode)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				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
    }