Skip to content
Snippets Groups Projects
main.go 25.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • Nicolas PERNOUD's avatar
    Nicolas PERNOUD committed
    package main
    
    import (
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    	"encoding/base64"
    
    Hugo's avatar
    Hugo committed
    	"encoding/json"
    
    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"
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    	"os"
    
    Hugo's avatar
    Hugo committed
    	"reflect"
    
    Nicolas PERNOUD's avatar
    Nicolas PERNOUD committed
    	"strconv"
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    	"strings"
    
    Hugo's avatar
    Hugo committed
    
    
    Sébastien Blaisot's avatar
    Sébastien Blaisot committed
    	log "github.com/sirupsen/logrus"
    
    Hugo's avatar
    Hugo 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)")
    	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)")
    	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 {
    
    Hugo's avatar
    Hugo committed
    	AccessToken  string `json:"access_token"`
    	RefreshToken string `json:"refresh_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 {
    	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
    }
    
    
    Hugo's avatar
    Hugo committed
    func logRoute(key string) {
    	// format is : Subject - action - location - description
    	switch key {
    	case "Ping_enedis_new_auth":
    
    		log.Info("Enedis - Received - Authorize - new /auth request from Cozy")
    
    Hugo's avatar
    Hugo committed
    	case "Ping_enedis_redirect":
    
    		log.Info("Enedis - Received - Redirect")
    
    Hugo's avatar
    Hugo committed
    	case "Ping_enedis_new_token":
    
    		log.Info("Enedis - Received - Token - new /token request from Cozy")
    
    Hugo's avatar
    Hugo committed
    	case "Ping_enedis_oauth_token":
    
    		log.Info("Enedis - Received - Token - an oauth token request from Cozy")
    
    Hugo's avatar
    Hugo committed
    	case "Ping_enedis_refresh":
    
    		log.Info("Enedis - Received - Token - a refresh token request from Cozy")
    
    Hugo's avatar
    Hugo committed
    
    	case "Ping_grdf_new_auth":
    
    		log.Info("Grdf - Received - Authorize - new /auth request from Cozy")
    
    Hugo's avatar
    Hugo committed
    	case "Ping_grdf_redirect":
    
    		log.Info("Grdf - Received - Redirect")
    
    Hugo's avatar
    Hugo committed
    	case "Ping_grdf_new_token":
    
    		log.Info("Grdf - Received - Token - new /token request from Cozy")
    
    Hugo's avatar
    Hugo committed
    
    
    		log.Info("Enedis - Success - Oauth - oauth dance successfully done")
    
    Hugo's avatar
    Hugo committed
    	case "Enedis_success_token":
    
    		log.Info("Enedis - Success - Token - Enedis gave a new token or refresh token to the cozy stack")
    
    Hugo's avatar
    Hugo committed
    	case "Grdf_success":
    
    		log.Info("Grdf - Success - Oauth - oauth dance successfully done")
    
    Hugo's avatar
    Hugo committed
    	case "Grdf_success_token":
    
    		log.Info("Grdf - Success - Token - Grdf gave a new token to the cozy stack")
    
    Hugo's avatar
    Hugo committed
    
    	case "Enedis_error":
    
    		log.Error("Enedis - Error - Oauth - something wrong happened with enedis")
    
    Hugo's avatar
    Hugo committed
    	case "Enedis_redirect_error":
    
    		log.Error("Enedis - Error - Redirect - an error occured with enedis redirection")
    
    Hugo's avatar
    Hugo committed
    	case "Enedis_token_error":
    
    		log.Error("Enedis - Error - Token - an error occured with enedis /token endpoint")
    
    Hugo's avatar
    Hugo committed
    
    	case "Grdf_error":
    
    		log.Error("Grdf - Error - Oauth - something wrong happened with grdf")
    
    Hugo's avatar
    Hugo committed
    	case "Grdf_redirect_error":
    
    		log.Error("Grdf - Error - Redirect - an error occured with grdf redirection")
    
    Hugo's avatar
    Hugo committed
    	case "Grdf_token_error":
    
    		log.Error("Grdf - Error - Token - an error occured with grdf /token endpoint")
    
    Hugo's avatar
    Hugo committed
    
    	case "Proxy_error":
    		log.Error("Proxy - Error - Oauth - something wrong happened in the proxy")
    
    	case "Proxy_error_enedis_auth":
    		log.Error("Proxy - Error - Enedis - Authorize")
    	case "Proxy_error_grdf_auth":
    		log.Error("Proxy - Error - Grdf - Authorize")
    
    	case "Proxy_error_enedis_redirect":
    		log.Error("Proxy - Error - Enedis - Redirect")
    	case "Proxy_error_grdf_redirect":
    		log.Error("Proxy - Error - Grdf - Redirect")
    
    	case "Proxy_error_enedis_token":
    		log.Error("Proxy - Error - Enedis - Token")
    	case "Proxy_error_grdf_token":
    		log.Error("Proxy - Error - Grdf - Token")
    
    	case "Cozy_error_enedis_auth":
    		log.Error("Cozy - Error - Enedis - Authorize")
    	case "Cozy_error_grdf_auth":
    		log.Error("Cozy - Error - Grdf - Authorize")
    
    	default:
    
    		log.Info("logRoute was called with unknown arguments")
    
    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) {
    
    Hugo's avatar
    Hugo committed
    		logRoute("Ping_enedis_new_auth")
    
    		query := r.URL.Query()
    
    		//log.Debug("WL - EnedisReceived - Authorize - Query received from Cozy: ", query)
    		log.Info("WL - EnedisReceived - Authorize - Query received from Cozy")
    
    
    		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")
    
    Hugo's avatar
    Hugo committed
    		if len(clientId) > 0 && len(state) > 0 && len(cozyOrigin) > 0 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			splitIndexStart := strings.Index(cozyOrigin, ":")
    			splitIndexEnd := strings.Index(cozyOrigin, ".")
    			if splitIndexStart > -1 && splitIndexEnd > -1 {
    
    Hugo's avatar
    Hugo committed
    				instanceName := cozyOrigin[splitIndexStart+3 : splitIndexEnd]
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				// 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=P12M&response_type=" + responseType + "&state=" + state + "-" + instanceName
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    				log.Info("WL - EnedisSuccess - Authorize - Redirecting user to Enedis")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				http.Redirect(w, r, redirectUrl, 302)
    			} else {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Proxy_error_enedis_auth")
    
    				log.Error("WL - ProxyError - Enedis - Authorize - redirect_uri bad format from Cozy " + cozyOrigin)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				http.Error(w, http.StatusText(500), 500)
    			}
    		} else {
    
    Hugo's avatar
    Hugo committed
    			logRoute("Cozy_error_enedis_auth")
    
    			log.Info("WL - CozyError - Enedis - Authorize - Missing parameters in request")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			http.Error(w, http.StatusText(500), 500)
    
    Hugo's avatar
    Hugo committed
    		}
    
    	// GRDF ADICT AUTHORIZE ENDPOINT
    	mux.HandleFunc("/grdf_authorize", func(w http.ResponseWriter, r *http.Request) {
    
    Hugo's avatar
    Hugo committed
    		logRoute("Ping_grdf_new_auth")
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    		query := r.URL.Query()
    
    		//log.Debug("WL - GrdfReceived - Authorize - Query received: ", query)
    		log.Info("WL - GrdfReceived - Authorize - Query received")
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    
    		clientId := query.Get("client_id")
    		state := query.Get("state")
    		cozyOrigin := query.Get("redirect_uri")
    
    Hugo's avatar
    Hugo committed
    		if len(clientId) > 0 && len(state) > 0 && len(cozyOrigin) > 0 {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			splitIndexStart := strings.Index(cozyOrigin, ":")
    			splitIndexEnd := strings.Index(cozyOrigin, ".")
    			if splitIndexStart > -1 && splitIndexEnd > -1 {
    
    Hugo's avatar
    Hugo committed
    				instanceName := cozyOrigin[splitIndexStart+3 : splitIndexEnd]
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				redirectProxy := *cozyProxyURI + "/redirect-grdf"
    				authURL := "https://sofit-sso-oidc.grdf.fr/openam/oauth2/realms/externeGrdf/authorize"
    
    Hugo's avatar
    Hugo committed
    
    
    				redirectUrl := authURL + "?client_id=" + clientId + "&scope=openid&response_type=code&redirect_uri=" + redirectProxy + "&login_hint=Prénom%7cNom%7c%7cEcolyo&state=" + state + "-" + instanceName
    
    Hugo's avatar
    Hugo committed
    
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    				log.Info("WL - GrdfSuccess - Authorize - Redirect user")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				http.Redirect(w, r, redirectUrl, 302)
    			} else {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Proxy_error_grdf_auth")
    
    				log.Error("WL - ProxyError - Grdf - Authorize - redirect_uri bad format from Cozy " + cozyOrigin)
    
    Hugo's avatar
    Hugo committed
    				http.Error(w, http.StatusText(500), 500)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			}
    		} else {
    
    Hugo's avatar
    Hugo committed
    			logRoute("Cozy_error_grdf_auth")
    
    			log.Info("WL - CozyError - 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) {
    
    Hugo's avatar
    Hugo committed
    		logRoute("Ping_enedis_redirect")
    
    		query := r.URL.Query()
    
    		//log.Debug("WL - EnedisReceived - Redirect - Query received: ", query)
    		log.Info("WL - EnedisReceived - Redirect - Query received")
    
    
    		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 {
    
    Hugo's avatar
    Hugo committed
    					logRoute("Proxy_error_enedis_redirect")
    
    					log.Error("WL - ProxyError - Enedis - Redirect - String to int convert error for status code: ", err)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    					http.Error(w, http.StatusText(500), 500)
    					return
    				}
    
    Hugo's avatar
    Hugo committed
    				logRoute("Enedis_redirect_error")
    
    				log.Error("WL - EnedisError - Redirect - status code error: ", code)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				http.Error(w, http.StatusText(intCode), intCode)
    				return
    
    			splitIndex := strings.Index(req_state, "-")
    			if splitIndex == -1 {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Proxy_error_enedis_redirect")
    
    				log.Error("WL - 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
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    			log.Info("WL - EnedisSuccess - Redirect - Redirecting user to  Cozy stack")
    
    			http.Redirect(w, r, redir, 302)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		} else {
    
    			if len(code) > 0 {
    				if findItem(statusCodes, code) {
    					intCode, err := strconv.Atoi(code)
    					if err != nil {
    						logRoute("Proxy_error_enedis_redirect")
    						log.Error("WL - ProxyError - Enedis - Redirect - String to int convert error for status code: ", err)
    						http.Error(w, http.StatusText(500), 500)
    						return
    					}
    					logRoute("Enedis_redirect_error")
    					log.Error("WL - EnedisError - Redirect - status code error: ", code)
    					http.Error(w, http.StatusText(intCode), intCode)
    					return
    				}
    			}
    
    Hugo's avatar
    Hugo committed
    			logRoute("Proxy_error_enedis_redirect")
    
    			log.Error("WL - ProxyError - Enedis - Redirect - Missing parameters in request")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			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) {
    
    Hugo's avatar
    Hugo committed
    		logRoute("Enedis_redirect_error")
    		log.Error("WL - EnedisError - Redirect - Wrong route received from Enedis ")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		http.Error(w, http.StatusText(500), 500)
    	})
    
    
    	//GRDF REDIRECT ENDPOINT
    	mux.HandleFunc("/redirect-grdf", func(w http.ResponseWriter, r *http.Request) {
    
    Hugo's avatar
    Hugo committed
    		logRoute("Ping_grdf_redirect")
    
    		query := r.URL.Query()
    
    		//log.Debug("WL - GrdfReceived - Redirect - Received redirect answer from GRDF: ", query)
    		log.Info("WL - GrdfReceived - Redirect - Received redirect answer from GRDF")
    
    
    		code := query.Get("code")
    		req_state := query.Get("state")
    
    Hugo's avatar
    Hugo committed
    
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		if len(code) > 0 && len(req_state) > 0 {
    			splitIndex := strings.Index(req_state, "-")
    			if splitIndex == -1 {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Proxy_error_grdf_redirect")
    				log.Error("WL - ProxyError - Grdf - Redirect - No host found")
    
    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:]
    
    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
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    			log.Info("WL - GrdfSuccess - Redirect - Redirect to Cozy stack")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			http.Redirect(w, r, redir, 302)
    		} else {
    
    Hugo's avatar
    Hugo committed
    			logRoute("Proxy_error_grdf_redirect")
    			log.Error("WL - ProxyError - Grdf - Redirect - Missing parameters in request")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			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) {
    
    Hugo's avatar
    Hugo committed
    		logRoute("Ping_enedis_new_token")
    
    		query := r.URL.Query()
    
    		// log.Debug("WL - EnedisReceived - Token - Received new token request from Cozy: ", query)
    		log.Info("WL - EnedisReceived - Token - Received new token request from Cozy")
    
    		clientId := ""
    		clientSecret := ""
    		code := ""
    		grantType := ""
    		refreshToken := ""
    
    		// For request token params are into query parameters
    
    		if len(query) == 0 {
    
    			log.Info("WL - EnedisInfo - Token - No params found in url query, trying to catch them from body")
    
    			contents, err := ioutil.ReadAll(r.Body)
    			if err != nil {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Proxy_error_enedis_token")
    				log.Error("WL - ProxyError - Enedis - Token - Unable to read the body: ", err)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				http.Error(w, err.Error(), 500)
    				return
    
    Hugo's avatar
    Hugo committed
    			}
    
    			params, err := url.ParseQuery(string(contents))
    			if err != nil {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Proxy_error_enedis_token")
    				log.Error("WL - ProxyError - Enedis - Token - Unable to parse 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["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
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    		// log.WithFields(log.Fields{
    		// 	"client_id":     clientId,
    		// 	"client_secret": clientSecret,
    		// 	"code":          code,
    		// 	"grant_type":    grantType,
    		// 	"refresh_token": refreshToken,
    		// }).Debug("WL - EnedisInfo - Token - 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 != "" {
    
    Hugo's avatar
    Hugo committed
    			logRoute("Ping_enedis_refresh")
    
    			log.Info("WL - EnedisReceived - Token - Cozystack asks for a new refresh token")
    
    			data.Set("refresh_token", refreshToken)
    			data.Set("grant_type", "refresh_token")
    
    Hugo's avatar
    Hugo committed
    		} else {
    			logRoute("Ping_enedis_oauth_token")
    
    			log.Info("WL - EnedisReceived - Token - Cozystack asks for a regular token to end the oauth dance")
    
    		log.Info("WL - EnedisInfo - Token - Send request to Enedis token endpoint: ", tokenUrl)
    
    		response, err := http.PostForm(tokenUrl, data)
    
    		if err != nil {
    
    Hugo's avatar
    Hugo committed
    			logRoute("Proxy_error_enedis_token")
    			log.Error("WL - ProxyError - Enedis - Token - Unable to post the request: ", err)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			http.Error(w, http.StatusText(500), 500)
    			return
    
    Hugo's avatar
    Hugo committed
    		}
    
    		log.Info("WL - EnedisInfo - Token - Enedis answered back with status ", response.Status)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		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 {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Proxy_error_enedis_token")
    				log.Error("WL - ProxyError - Enedis - Token - Unable to decode data: ", decodeError)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				http.Error(w, decodeError.Error(), 500)
    				return
    			}
    			// Response with json data
    			jsonError := json.NewEncoder(w).Encode(data)
    			if jsonError != nil {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Proxy_error_enedis_token")
    				log.Error("WL - ProxyError - Enedis - Token - Unable to encode data: ", jsonError)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				http.Error(w, jsonError.Error(), 500)
    				return
    
    			if refreshToken != "" {
    				logRoute("Enedis_success_token")
    			} else {
    				logRoute("Enedis_success_oauth")
    			}
    
    Hugo's avatar
    Hugo committed
    			log.Info("WL - EnedisSuccess - Token - Respond correctly to Cozy stack")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		} else {
    
    Hugo's avatar
    Hugo committed
    			logRoute("Enedis_token_error")
    			log.Error("WL - EnedisError - Token - Enedis answer back with status code: ", response.StatusCode)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			http.Error(w, http.StatusText(response.StatusCode), response.StatusCode)
    
    	//GRDF TOKEN ENDPOINT
    	mux.HandleFunc("/grdf_token", func(w http.ResponseWriter, r *http.Request) {
    
    Hugo's avatar
    Hugo committed
    		logRoute("Ping_grdf_new_token")
    
    		query := r.URL.Query()
    
    		// log.Debug("WL - GrdfReceived - Token - Received new token request from Cozy", query)
    		log.Info("WL - GrdfReceived - Token - Received new token request from Cozy")
    
    
    		clientId := ""
    		clientSecret := ""
    		code := ""
    		grantType := ""
    
    		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 {
    
    			log.Info("WL - GrdfInfo - 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 {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Proxy_error_grdf_token")
    				log.Error("WL - ProxyError - Grdf - Token - Unable to read the body: ", err)
    
    				http.Error(w, err.Error(), 500)
    				return
    
    			params, err := url.ParseQuery(string(contents))
    			if err != nil {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Proxy_error_grdf_token")
    				log.Error("WL - ProxyError - 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
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    		// log.WithFields(log.Fields{
    		// 	"client_id":     clientId,
    		// 	"client_secret": clientSecret,
    		// 	"code":          code,
    		// 	"grant_type":    grantType,
    		// 	"redirect_uri":  redirectUri,
    		// 	"scope":         scope,
    		// }).Debug("WL - GrdfInfo - Token - Result")
    
    
    		tokenUrl := "https://sofit-sso-oidc.grdf.fr/openam/oauth2/realms/externeGrdf/access_token"
    
    
    Hugo's avatar
    Hugo committed
    		if grantType != "refresh_token" {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			// 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)
    
    			// log.Debug("WL - GrdfInfo - Token - data sent is: ", data)
    			log.Info("WL - GrdfInfo - 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 {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Proxy_error_grdf_token")
    				log.Error("WL - ProxyError - Grdf - Token - Unable to post the request: ", err)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				http.Error(w, http.StatusText(500), 500)
    				return
    			}
    
    			log.Info("WL - GrdfInfo - 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 {
    
    Hugo's avatar
    Hugo committed
    					logRoute("Proxy_error_grdf_token")
    					log.Error("WL - ProxyError - 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
    				// 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("WL - GrdfInfo - Token - token decoded payload: ", 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 {
    
    Hugo's avatar
    Hugo committed
    							logRoute("Proxy_error_grdf_token")
    							log.Error("WL - ProxyError - 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("WL - GrdfInfo - Token - Consentements found: ", token.Consentements)
    						log.Info("WL - GrdfInfo - Token - Consentements found")
    
    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 {
    
    Hugo's avatar
    Hugo committed
    								logRoute("Proxy_error_grdf_token")
    								log.Error("WL - ProxyError - 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
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				if len(pce) <= 0 {
    
    Hugo's avatar
    Hugo committed
    					logRoute("Proxy_error_grdf_token")
    					log.Error("WL - ProxyError - Grdf - Token - No PCE found")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    					http.Error(w, http.StatusText(500), 500)
    					return
    				}
    			} else {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Grdf_token_error")
    				log.Error("WL - GrdfError - Token - GRDF response with status code: ", response.StatusCode)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				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/v2")
    
    		// log.Debug("WL - GrdfInfo - Token - data sent is: ", data2)
    		log.Info("WL - GrdfInfo - 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 {
    
    Hugo's avatar
    Hugo committed
    			logRoute("Proxy_error_grdf_token")
    			log.Error("WL - ProxyError - Grdf - Token - Unable to post the request: ", err2)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			http.Error(w, http.StatusText(500), 500)
    			return
    
    Hugo's avatar
    Hugo committed
    		}
    
    		log.Info("WL - GrdfInfo - 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{}
    			decodeError := json.NewDecoder(response2.Body).Decode(&data)
    			if decodeError != nil {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Proxy_error_grdf_token")
    				log.Error("WL - ProxyError - Grdf - Token - Unable to decode data: ", decodeError)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				http.Error(w, decodeError.Error(), 500)
    				return
    
    Hugo's avatar
    Hugo committed
    			if grantType != "refresh_token" {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				data.RefreshToken = "-"
    				data.Pce = pce
    				data.IdToken = IdToken
    			}
    
    Hugo's avatar
    Hugo committed
    
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    			jsonError := json.NewEncoder(w).Encode(data)
    			if jsonError != nil {
    
    Hugo's avatar
    Hugo committed
    				logRoute("Proxy_error_grdf_token")
    				log.Error("WL - ProxyError - Grdf - Token - Unable to encode data: ", jsonError)
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    				http.Error(w, jsonError.Error(), 500)
    				return
    			}
    
    Hugo's avatar
    Hugo committed
    			logRoute("Grdf_success_token")
    			log.Info("WL - GrdfSuccess - Token - Response correctly to Cozy stack")
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    		} else {
    
    Hugo's avatar
    Hugo committed
    			logRoute("Grdf_token_error")
    			log.Error("WL - GrdfError - 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
    }