Skip to content

Commit

Permalink
[GCloud][Auth] Add GCloudServiceAccount middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
danysousa committed Nov 22, 2022
1 parent c368326 commit f092bf6
Show file tree
Hide file tree
Showing 6 changed files with 1,292 additions and 0 deletions.
15 changes: 15 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
### Go ###
# Binaries for programs and plugins
*.exe
*.exe~
Expand All @@ -13,3 +14,17 @@

# Dependency directories (remove the comment below to include it)
# vendor/

### Go Patch ###
vendor
Godeps/


# JetBrain
/.idea

#.DS_Store
.DS_Store

# .gcloudignore
*.gcloudignore
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# GAPI Addons

-----

A repo with a list of additional packages to improve GAPI features

## How it works

-----

First choose your package(s) and add it using go modules, here is an example for [auth.GCloudServiceAccount](https://pkg.go.dev/github.com/mwm-io/gapi-addons/gcloud/middleware/auth#GCloudServiceAccount):
```sh
$ get get github.com/mwm-io/gapi-addons/gcloud/middleware/auth@latest
```

The use it in you code:

```go
package main

import (
...
github.com/mwm-io/gapi-addons/gcloud/middleware/auth
)

type myHandler struct {
handler.WithMiddlewares
}

func NewHandler() handler.Handler {
var h myHandler

h.MiddlewareList = []handler.Middleware{
auth.GCloudServiceAccount{
ServiceAccount: "[email protected]",
},
}
...
}
```

1 change: 1 addition & 0 deletions gcloud/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
> All Google Cloud specific packages must be here.
102 changes: 102 additions & 0 deletions gcloud/middleware/auth/gcloud_service_account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package auth

import (
"net/http"
"strings"

"github.com/mwm-io/gapi/errors"
"github.com/mwm-io/gapi/handler"
"github.com/mwm-io/gapi/openapi"
"github.com/swaggest/openapi-go/openapi3"
"google.golang.org/api/idtoken"
)

// AuthorizationHeader const for header used for authorization token
const AuthorizationHeader = "Authorization"

// GCloudServiceAccount is a middleware that will check AuthorizationHeader for incoming request.
// The expected header value is an OpenID Token generated by Google Cloud for given ServiceAccount.
type GCloudServiceAccount struct {
ServiceAccount string
}

// Wrap implements the handler.Middleware interface
func (m GCloudServiceAccount) Wrap(h handler.Handler) handler.Handler {
return handler.Func(func(w http.ResponseWriter, r *http.Request) (interface{}, error) {
token := r.Header.Get(AuthorizationHeader)
if token == "" {
return nil, errors.Err("access forbidden").WithStatus(http.StatusForbidden)
}

splitAuthHeader := strings.Split(token, " ")
if len(splitAuthHeader) == 0 {
return nil, errors.Err("access forbidden").WithStatus(http.StatusForbidden)
}

payload, err := idtoken.Validate(r.Context(), splitAuthHeader[1], "")
if err != nil {
// invalid token
return nil, errors.Err("access forbidden").WithStatus(http.StatusForbidden)
}

if payload.Issuer != "accounts.google.com" && payload.Issuer != "https://accounts.google.com" {
return nil, errors.Err("access forbidden").WithStatus(http.StatusForbidden)
}

if payload.Claims == nil {
return nil, errors.Err("access forbidden").WithStatus(http.StatusForbidden)
}

if emailVerified := payload.Claims["email_verified"].(bool); !emailVerified && payload.Claims["email_verified"] != "true" {
return nil, errors.Err("access forbidden").WithStatus(http.StatusForbidden)
}

if payload.Claims["email"] != m.ServiceAccount {
return nil, errors.Err("access forbidden").WithStatus(http.StatusForbidden)
}

return h.Serve(w, r)
})
}

const securitySchemeKey = "gcloud_service_account"

// Doc implements the openapi.Documented interface
func (m GCloudServiceAccount) Doc(builder *openapi.DocBuilder) error {
_, ok := builder.Reflector().
SpecEns().
ComponentsEns().
SecuritySchemesEns().
MapOfSecuritySchemeOrRefValues[securitySchemeKey]

if !ok {
openIDScheme := new(openapi3.SecurityScheme).
WithOpenIDConnectSecurityScheme(
*new(openapi3.OpenIDConnectSecurityScheme).
WithDescription(`
This auth middleware is useful for endpoint called by a GCloud service for example:
- Cloud Scheduler: https://cloud.google.com/scheduler/docs/http-target-auth
- Pub/Sub: https://cloud.google.com/pubsub/docs/push#authentication
`),
)

authSchema := *new(openapi3.SecuritySchemeOrRef).WithSecurityScheme(*openIDScheme)
builder.Reflector().
SpecEns().
ComponentsEns().
SecuritySchemesEns().
WithMapOfSecuritySchemeOrRefValuesItem(
securitySchemeKey,
authSchema,
)
}

builder.Operation().
WithSecurity(map[string][]string{
securitySchemeKey: {
m.ServiceAccount,
},
})

return nil
}
9 changes: 9 additions & 0 deletions gcloud/middleware/auth/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module github.com/mwm-io/gapi-addons/gcloud/middleware/auth

go 1.16

require (
github.com/mwm-io/gapi v0.0.1
github.com/swaggest/openapi-go v0.2.26
google.golang.org/api v0.103.0
)
Loading

0 comments on commit f092bf6

Please sign in to comment.