Newer
Older
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.wf.alpha.grandlyon.com"), "Cozy domain (defaults to cozy.wf.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_redirect_uri", LookupEnvOrString("COZY_REDIRECT_URI", "/accounts/grdfgrandlyon/redirect"), "Cozy redirect URI (defaults to /accounts/grdfgrandlyon/redirect)")
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"`
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
}
func main() {
// Parse the flags
flag.Parse()
// 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)
}
log.Infof("Starting Server on port %d\n", *httpPort)
mux.HandleFunc("/healthcheck", func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "OK\n")
})
mux.HandleFunc("/auth", func(w http.ResponseWriter, r *http.Request) {
clientId := query.Get("client_id")
state := query.Get("state")
// 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 {
log.Error("redirect_uri bad format " + cozyOrigin)
http.Error(w, http.StatusText(500), 500)
}
splitIndexEnd := strings.Index(cozyOrigin, ".")
if splitIndexEnd == -1 {
log.Error("redirect_uri bad format " + cozyOrigin)
http.Error(w, http.StatusText(500), 500)
}
instanceName := cozyOrigin[splitIndexStart+3:splitIndexEnd]
// authURL := "https://gw.hml.api.enedis.fr/dataconnect/v1/oauth2/authorize"
authURL := "https://mon-compte-particulier.enedis.fr/dataconnect/v1/oauth2/authorize"
redirectUrl := authURL + "?client_id=" + clientId + "&duration=P6M&response_type=" + responseType + "&state=" + state + "-" + instanceName
http.Redirect(w, r, redirectUrl, 302)
// GRDF ADICT AUTHORIZE ENDPOINT
mux.HandleFunc("/grdf_authorize", func(w http.ResponseWriter, r *http.Request) {
log.Debug("New grdf auth request")
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 {
log.Error("redirect_uri bad format " + cozyOrigin)
http.Error(w, http.StatusText(500), 500)
}
splitIndexEnd := strings.Index(cozyOrigin, ".")
if splitIndexEnd == -1 {
log.Error("redirect_uri bad format " + cozyOrigin)
http.Error(w, http.StatusText(500), 500)
}
instanceName := cozyOrigin[splitIndexStart+3:splitIndexEnd]
redirectProxy := "https://oauth-proxy.wf.alpha.grandlyon.com"
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 + "&state=" + state + "-" + instanceName
// TODO Add Login Hint in request
log.Debug("Redirect to - ", redirectUrl)
http.Redirect(w, r, redirectUrl, 302)
})
//ENEDIS REDIRECT ENDPOINT
mux.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) {
req_state := query.Get("state")
statusCodes := [4]string{"400", "403", "500", "503"}
if (findItem(statusCodes, code)) {
intCode, err := strconv.Atoi(code)
if err != nil {
log.Print("status code string to int error: ", err)
}
log.Print("status code error : ", code)
http.Error(w, http.StatusText(intCode), intCode)
} else {
splitIndex := strings.Index(req_state, "-")
if splitIndex == -1 {
log.Warning("No host found")
}
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
log.Debug("Redirect to -", redir)
http.Redirect(w, r, redir, 302)
}
//GRDF REDIRECT ENDPOINT
mux.HandleFunc("/redirect-grdf", func(w http.ResponseWriter, r *http.Request) {
log.Debug("New redirection on grdf-redirect")
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 {
log.Warning("No host found")
}
state := req_state[0:splitIndex]
host := req_state[splitIndex+1:]
cozyURL := "https://" + host + "." + *cozyDomain + *cozyGrdfRedirectURI
redir := cozyURL + "?code=" + code + "&state=" + state
log.Debug("Redirect to -", redir)
http.Redirect(w, r, redir, 302)
})
mux.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
clientId := ""
clientSecret := ""
code := ""
grantType := ""
refreshToken := ""
// For request token params are into query parameters
log.Warn("No params found in url query - Trying to catch them from body")
contents, err := ioutil.ReadAll(r.Body)
if err != nil {
}
pageContent := string(contents)
//Check for client_id
clientIdStartIndex := strings.Index(pageContent, "client_id=")
if clientIdStartIndex == -1 {
http.Error(w, http.StatusText(500), 500)
}
clientIdStartIndex += 10
clientId = pageContent[clientIdStartIndex : clientIdStartIndex+36]
//Check for client_secret
clientSecretStartIndex := strings.Index(pageContent, "client_secret=")
if clientSecretStartIndex == -1 {
http.Error(w, http.StatusText(500), 500)
}
clientSecretStartIndex += 14
clientSecret = pageContent[clientSecretStartIndex : clientSecretStartIndex+36]
//Check for code
codeStartIndex := strings.Index(pageContent, "code=")
if codeStartIndex == -1 {
log.Info("No code found (optional param)")
} else {
codeStartIndex += 5
}
//Check for grant_type
grandTypeStartIndex := strings.Index(pageContent, "grant_type=")
if grandTypeStartIndex == -1 {
http.Error(w, http.StatusText(500), 500)
}
grandTypeStartIndex += 11
grandTypeEndIndex := strings.Index(tempGrandTypeString, "&")
if grandTypeEndIndex == -1 {
http.Error(w, http.StatusText(500), 500)
}
grantType = tempGrandTypeString[0:grandTypeEndIndex]
//Check for refresh_token
refershTokenStartIndex := strings.Index(pageContent, "refresh_token=")
if refershTokenStartIndex == -1 {
}
refershTokenStartIndex += 14
refreshToken = pageContent[refershTokenStartIndex : refershTokenStartIndex+46]
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
log.WithFields(log.Fields{
"client_id": clientId,
"client_secret": clientSecret,
"code": code,
"grant_type": grantType,
"refresh_token": refreshToken,
}).Debug("result")
// tokenUrl := "https://gw.hml.api.enedis.fr/v1/oauth2/token"
tokenUrl := "https://gw.prd.api.enedis.fr/v1/oauth2/token"
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")
}
log.Debug("Send request to token endpoint: ", tokenUrl)
response, err := http.PostForm(tokenUrl, data)
log.Debug("Endpoint response with status", response.Status)
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 := TokenResponse{}
decodeError := json.NewDecoder(response.Body).Decode(&data)
if decodeError != nil {
http.Error(w, decodeError.Error(), 500)
return
}
// Response with json data
jsonError := json.NewEncoder(w).Encode(data)
if jsonError != nil {
http.Error(w, jsonError.Error(), 500)
return
}
} else {
http.Error(w, http.StatusText(response.StatusCode), response.StatusCode)
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
//GRDF TOKEN ENDPOINT
mux.HandleFunc("/grdf_token", func(w http.ResponseWriter, r *http.Request) {
log.Debug("New GRDF token request")
query := r.URL.Query()
log.Debug(query)
clientId := ""
clientSecret := ""
code := ""
grantType := ""
scope := ""
// For request token params are into query parameters
// Retrieve params from query
clientId = query.Get("client_id")
clientSecret = query.Get("client_secret")
code = query.Get("code")
grantType = query.Get("grant_type")
scope = query.Get("scope")
// Print out the result
log.WithFields(log.Fields{
"client_id": clientId,
"client_secret": clientSecret,
"code": code,
"grant_type": grantType,
"scope": scope,
}).Debug("result")
tokenUrl := "https://sofit-sso-oidc.grdf.fr/openam/oauth2/realms/externeGrdf/access_token"
data := url.Values{}
data.Set("client_id", clientId)
data.Set("client_secret", clientSecret)
data.Set("grant_type", grantType)
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
data.Set("scope", scope)
}
log.Debug("Send request to token endpoint: ", tokenUrl)
response, err := http.PostForm(tokenUrl, data)
if err != nil {
log.Error(err)
} else {
log.Debug("Endpoint response with status", response.Status)
defer response.Body.Close()
if response.StatusCode >= 200 && response.StatusCode <= 299 {
// Set Content-Type in response header
w.Header().Add("Content-Type", "application/json")
// Decode response Body using the defined type "TokenResponse"
data := TokenResponse{}
decodeError := json.NewDecoder(response.Body).Decode(&data)
if decodeError != nil {
http.Error(w, decodeError.Error(), 500)
return
}
// Response with json data
jsonError := json.NewEncoder(w).Encode(data)
if jsonError != nil {
http.Error(w, jsonError.Error(), 500)
return
}
} else {
http.Error(w, http.StatusText(response.StatusCode), response.StatusCode)
}
}
})
log.Fatal(http.ListenAndServe(":"+strconv.Itoa(*httpPort), mux))