package verify import ( "bytes" "encoding/json" "io" http "net/http" "net/url" "github.com/MicahParks/keyfunc" "github.com/coreos/go-oidc/v3/oidc" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v4" "golang.org/x/oauth2" "edge-infra.dev/pkg/edge/iam/log" ) func (v *Verifier) scanBarcode(ctx *gin.Context) { log := log.Get(ctx.Request.Context()) // Access the form data barcode := ctx.Query("barcode") if barcode == "" { log.Info("No barcode value found") ctx.AbortWithStatus(http.StatusBadRequest) return } // setting the http body in x-www-form-urlencoded form data := url.Values{} data.Set("client_id", v.ClientID) data.Set("client_secret", v.ClientSecret) data.Set("grant_type", "barcode") data.Set("barcode", barcode) // Make a POST request to the token endpoint res, err := http.Post(IssuerURL()+oauth2TokenPath, gin.MIMEPOSTForm, bytes.NewBufferString(data.Encode())) if err != nil { log.Info("failed to get token from barcode scan", "error", err) err := ctx.AbortWithError(http.StatusInternalServerError, err) if err != nil { log.Error(err, "failed to abort with error") } return } defer res.Body.Close() if res.StatusCode != http.StatusOK { loginhint := res.Header.Get("WWW-Authenticate") if loginhint == "" { ctx.AbortWithStatus(res.StatusCode) return } provider, err := oidc.NewProvider(oidc.InsecureIssuerURLContext(ctx, Issuer()), IssuerURL()) if err != nil { err := ctx.AbortWithError(http.StatusInternalServerError, err) if err != nil { log.Error(err, "failed to abort with error") } return } config := oauth2.Config{ ClientID: v.ClientID, ClientSecret: v.ClientSecret, RedirectURL: v.ClientURL + verifyCallbackPath, Endpoint: provider.Endpoint(), Scopes: []string{oidc.ScopeOpenID, oidc.ScopeOfflineAccess, "profile"}, } // removing the first 6 charcters as it has "login {login_hint}" authCodeURL := config.AuthCodeURL("332b7b6ue34ds", oauth2.SetAuthURLParam("login_hint", loginhint[6:])) ctx.AbortWithStatusJSON(res.StatusCode, authCodeURL) return } // Read the response body of token endpoint body, err := io.ReadAll(res.Body) if err != nil { log.Error(err, "Error reading response") return } // Unmarshal the response JSON into a TokenResponse struct var tokenRes TokenResponse err = json.Unmarshal(body, &tokenRes) if err != nil { log.Error(err, "Error unmarshaling response") return } // accessing jwks (will be used for parsing the JWT token) jwksURL := IssuerURL() + wellKnownJWKSPath jwks, err := keyfunc.Get(jwksURL, keyfunc.Options{}) if err != nil { log.Info("failed get jwks", "error", err) err := ctx.AbortWithError(http.StatusInternalServerError, err) if err != nil { log.Error(err, "failed to abort with error") } return } // parse and validate the access token accessToken, err := jwt.Parse(tokenRes.AccessToken, jwks.Keyfunc) if err != nil { log.Info("failed to validate accesstoken", "error", err) err := ctx.AbortWithError(http.StatusInternalServerError, err) if err != nil { log.Error(err, "failed to abort with error") } return } if accessToken.Valid { ctx.AbortWithStatus(http.StatusOK) return } ctx.AbortWithStatus(http.StatusUnauthorized) }