github.com/aarzilli/tools@v0.0.0-20151123112009-0d27094f75e0/appengine/login/googlesignin/google_signin.go (about) 1 // package googlesignin offers a login completely based on client javascript; 2 // signin-signout being messaged accross devices; 3 // installation of apps can be triggered; 4 // it has no server side login comparable to appengine/login or appengine/login/gitkit. 5 package googlesignin 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "log" 11 "net/http" 12 "strings" 13 14 "github.com/pbberlin/tools/appengine/login" 15 "github.com/pbberlin/tools/appengine/login/googlesignin/jwt-go" 16 "github.com/pbberlin/tools/net/http/fetch" 17 "github.com/pbberlin/tools/net/http/loghttp" 18 "github.com/pbberlin/tools/net/http/routes" 19 "github.com/pbberlin/tools/stringspb" 20 ) 21 22 func init() { 23 http.HandleFunc("/tokensignin", TokenSignin) 24 } 25 26 // 27 // https://developers.google.com/identity/choose-auth 28 // https://developers.google.com/identity/sign-in/web/backend-auth 29 func TokenSignin(w http.ResponseWriter, r *http.Request) { 30 31 lg, _ := loghttp.BuffLoggerUniversal(w, r) 32 33 // w.Header().Set("Access-Control-Allow-Origin", "http://localhost:1313") 34 35 w.Header().Set("Access-Control-Allow-Origin", "http://"+routes.AppHostDev()) 36 37 w.Header().Del("Access-Control-Allow-Origin") 38 w.Header().Set("Access-Control-Allow-Origin", "*") 39 40 // err := r.ParseMultipartForm(1024 * 1024 * 2) 41 err := r.ParseForm() 42 lg(err) 43 44 myToken := r.Form.Get("idtoken") 45 tokSize := fmt.Sprintf("Len of Tok was %v. \n", len(myToken)) 46 47 fc1 := func(token *jwt.Token) (interface{}, error) { 48 // Don't forget to validate the alg is what you expect: 49 50 log.Printf("algo header is %v\n", token.Header["alg"]) 51 if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { 52 return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) 53 } 54 return token.Header["kid"], nil 55 } 56 57 token, err := jwt.Parse(myToken, fc1) 58 59 // No direct error comparison possible; since err is wrapped in another struct 60 if err != nil && strings.Contains(err.Error(), jwt.ErrPEMMappingObsolete.Error()) { 61 62 currentPEMsURL := "https://www.googleapis.com/oauth2/v1/certs" 63 req, err := http.NewRequest("GET", currentPEMsURL, nil) 64 if err != nil { 65 lg("creation of pem request failed") 66 return 67 } 68 req.Header.Set("Content-Type", "application/json") 69 70 fo := fetch.Options{Req: req} 71 fo.KnownProtocol = "https" 72 fo.ForceHTTPSEvenOnDevelopmentServer = true 73 bts, inf, err := fetch.UrlGetter(r, fo) 74 lg(err) 75 if err != nil { 76 lg("tried to fetch %v, %v", currentPEMsURL, inf.URL) 77 lg("msg %v", inf.Msg) 78 return 79 } 80 if len(bts) > 200 { 81 var data1 map[string]string 82 err = json.Unmarshal(bts, &data1) 83 lg(err) 84 // lg(stringspb.IndentedDumpBytes(data1)) 85 // w.Write(stringspb.IndentedDumpBytes(data1)) 86 if len(data1) > 1 { 87 lg("PEM mappings updated") 88 jwt.MappingToPEM = data1 89 } else { 90 lg("PEM mapping response contained only %v records; bytes length %v", len(data1), len(bts)) 91 } 92 } 93 94 } 95 96 token, err = jwt.Parse(myToken, fc1) 97 98 if err != nil && strings.Contains(err.Error(), jwt.ErrInvalidKey.Error()) { 99 w.Write([]byte("The submitted RSA Key was somehow unparseable. We still accept the token.\n")) 100 /* 101 https://developers.google.com/identity/sign-in/web/backend-auth 102 */ 103 err = nil 104 token.Valid = true 105 } 106 107 if err != nil { 108 w.Write([]byte("--- " + err.Error() + ".\n")) 109 } 110 111 if err == nil && token.Valid { 112 113 tk := "" 114 tk += fmt.Sprintf(" Algor: %v\n", token.Method) 115 tk += fmt.Sprintf(" Header: %v\n", token.Header) 116 for k, v := range token.Claims { 117 tk += fmt.Sprintf("\t %-8v %v\n", k, v) 118 } 119 lg(tk) 120 121 w.Write([]byte("tokensignin; valid. \n")) 122 w.Write([]byte(tokSize)) 123 sb := "header-sub-not-present" 124 if _, ok := token.Claims["sub"]; ok { 125 sb = token.Claims["sub"].(string) 126 } 127 w.Write([]byte("ID from PWT is " + sb + "\n")) 128 129 _, usr, msg1 := login.CheckForNormalUser(r) 130 if usr != nil { 131 w.Write([]byte("ID from SRV is " + usr.ID + "\n")) 132 } 133 w.Write([]byte(msg1 + "\n")) 134 135 } else { 136 w.Write([]byte("tokensignin; INVALID. \n")) 137 w.Write([]byte(tokSize)) 138 w.Write([]byte(stringspb.ToLen(myToken, 30))) 139 140 vrf := fmt.Sprintf("\nhttps://www.googleapis.com/oauth2/v3/tokeninfo?id_token=%v \n", myToken) 141 w.Write([]byte(vrf)) 142 } 143 144 }