|
@@ -0,0 +1,165 @@
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "fmt"
|
|
|
+ "io/ioutil"
|
|
|
+ "log"
|
|
|
+ "net"
|
|
|
+ "net/http"
|
|
|
+ "net/url"
|
|
|
+ "strings"
|
|
|
+
|
|
|
+ "github.com/valyala/fasttemplate"
|
|
|
+)
|
|
|
+
|
|
|
+//ClientInformationStruct export
|
|
|
+type ClientsInformationStruct []struct {
|
|
|
+ ClientID string `json:"client-id"`
|
|
|
+ ClientSecret string `json:"client-secret"`
|
|
|
+ Domain string `json:"domain"`
|
|
|
+ ServiceName string `json:"service-name"`
|
|
|
+ ServiceImage string `json:"service-image"`
|
|
|
+ Scope []string `json:"scope"`
|
|
|
+}
|
|
|
+
|
|
|
+func main() {
|
|
|
+ http.HandleFunc("/login", loginHandler)
|
|
|
+ http.Handle("/asset/", http.StripPrefix("/asset/", http.FileServer(http.Dir("./asset"))))
|
|
|
+
|
|
|
+ http.ListenAndServe(":8080", nil)
|
|
|
+}
|
|
|
+
|
|
|
+func loginHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
+ responseType, ok := r.URL.Query()["response_type"]
|
|
|
+ if !ok || len(responseType[0]) < 1 {
|
|
|
+ errHandler(w, r, "Url param response_type was missing")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if string(responseType[0]) != "code" {
|
|
|
+ errHandler(w, r, "Url param response_type was incompatible")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ clientID, ok := r.URL.Query()["client_id"]
|
|
|
+ if !ok || len(clientID[0]) < 1 {
|
|
|
+ errHandler(w, r, "Url param client_id was missing")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ redirectURI, ok := r.URL.Query()["redirect_uri"]
|
|
|
+ if !ok || len(redirectURI[0]) < 1 {
|
|
|
+ errHandler(w, r, "Url param redirect_uri was missing")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ redirectURIParsed, err := url.Parse(redirectURI[0])
|
|
|
+ host, _, _ := net.SplitHostPort(redirectURIParsed.Host)
|
|
|
+
|
|
|
+ scope, ok := r.URL.Query()["scope"]
|
|
|
+ if !ok || len(scope[0]) < 1 {
|
|
|
+ errHandler(w, r, "Url param scope was missing")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ state, ok := r.URL.Query()["state"]
|
|
|
+ if !ok || len(state[0]) < 1 {
|
|
|
+ errHandler(w, r, "Url param state was missing")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ nonce, ok := r.URL.Query()["nonce"]
|
|
|
+ if !ok || len(nonce[0]) < 1 {
|
|
|
+ errHandler(w, r, "Url param nonce was missing")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //let say the GET request was good, then let us find does client-id and domain match our record
|
|
|
+ data, err := ioutil.ReadFile("./client-id.json")
|
|
|
+ if err != nil {
|
|
|
+ fmt.Print(err)
|
|
|
+ }
|
|
|
+ var ClientsInformation ClientsInformationStruct
|
|
|
+ err = json.Unmarshal(data, &ClientsInformation)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("error:", err)
|
|
|
+ }
|
|
|
+ //process DB
|
|
|
+ DBClientID := ""
|
|
|
+ //DBClientSecret := ""
|
|
|
+ DBDomain := ""
|
|
|
+ DBServiceName := ""
|
|
|
+ DBServiceImage := ""
|
|
|
+ var DBScope []string
|
|
|
+ for _, ClientInformation := range ClientsInformation {
|
|
|
+ if ClientInformation.ClientID == clientID[0] {
|
|
|
+ DBClientID = ClientInformation.ClientID
|
|
|
+ //DBClientSecret = ClientInformation.ClientSecret
|
|
|
+ DBDomain = ClientInformation.Domain
|
|
|
+ DBServiceName = ClientInformation.ServiceName
|
|
|
+ DBServiceImage = ClientInformation.ServiceImage
|
|
|
+ DBScope = ClientInformation.Scope
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if DBClientID == "" {
|
|
|
+ errHandler(w, r, "client_id does not exist in our database.")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //check the record does it match
|
|
|
+ if DBDomain != host {
|
|
|
+ errHandler(w, r, "client_id and redirect_uri not match the system record.")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //check if scope is available for that client
|
|
|
+ scopeArr := strings.Split(scope[0], " ")
|
|
|
+ for _, scopeItem := range scopeArr {
|
|
|
+ if !contains(DBScope, scopeItem) {
|
|
|
+ errHandler(w, r, "scope not match our system record.")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //serve file
|
|
|
+ //push assembled data to page
|
|
|
+ parsedPage, err := templateLoad("login.html", map[string]interface{}{
|
|
|
+ "service-name": string(DBServiceName),
|
|
|
+ "service-image": string(DBServiceImage),
|
|
|
+ })
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ log.Println("Error. Unable to show error. Additionally, the error page also had error.")
|
|
|
+ }
|
|
|
+ w.Write([]byte(parsedPage))
|
|
|
+}
|
|
|
+
|
|
|
+func errHandler(w http.ResponseWriter, r *http.Request, errorMsg string) {
|
|
|
+ //push assembled data to page
|
|
|
+ parsedPage, err := templateLoad("error.html", map[string]interface{}{
|
|
|
+ "error": string(errorMsg),
|
|
|
+ })
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ log.Println("Error. Unable to show error. Additionally, the error page also had error.")
|
|
|
+ }
|
|
|
+ w.Write([]byte(parsedPage))
|
|
|
+ //sendTextResponse(w, parsedPage)
|
|
|
+}
|
|
|
+
|
|
|
+func templateLoad(filename string, replacement map[string]interface{}) (string, error) {
|
|
|
+ content, err := ioutil.ReadFile(filename)
|
|
|
+ if err != nil {
|
|
|
+ return "", nil
|
|
|
+ }
|
|
|
+ t := fasttemplate.New(string(content), "{{", "}}")
|
|
|
+ s := t.ExecuteString(replacement)
|
|
|
+ return string(s), nil
|
|
|
+}
|
|
|
+
|
|
|
+//https://ispycode.com/GO/Collections/Arrays/Check-if-item-is-in-array
|
|
|
+func contains(arr []string, str string) bool {
|
|
|
+ for _, a := range arr {
|
|
|
+ if a == str {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|