Deserializing claims fails for Auth0 Token - jwt

I'm using auth0 and am passing the generated token to the backend for some processing.
I need to validate the token and fetch some data from it (mainly email).
Checking the JWT on jwt.io and it appears valid with all relevant information there.
I'm using the provided auth0 middleware https://github.com/auth0/go-jwt-middleware to parse the token on my end. Everything runs fine until it gets to deserializeClaims.
I'm then hit with: could not get token claims: square/go-jose: unsupported key type/format)
Even just some insight on how to better troubleshoot this would be helpful, as it stands, I have no idea what is wrong.
// ValidateToken validates the passed in JWT using the jose v2 package.
func (v *Validator) ValidateToken(ctx context.Context, tokenString string) (interface{}, error) {
token, err := jwt.ParseSigned(tokenString)
if err != nil {
return nil, fmt.Errorf("could not parse the token: %w", err)
}
if err = validateSigningMethod(string(v.signatureAlgorithm), token.Headers[0].Algorithm); err != nil {
return nil, fmt.Errorf("signing method is invalid: %w", err)
}
registeredClaims, customClaims, err := v.deserializeClaims(ctx, token) <- this fails
if err != nil {
return nil, fmt.Errorf("failed to deserialize token claims: %w", err)
}
if err = validateClaimsWithLeeway(registeredClaims, v.expectedClaims, v.allowedClockSkew); err != nil {
return nil, fmt.Errorf("expected claims not validated: %w", err)
}
if customClaims != nil {
if err = customClaims.Validate(ctx); err != nil {
return nil, fmt.Errorf("custom claims not validated: %w", err)
}
}
validatedClaims := &ValidatedClaims{
RegisteredClaims: RegisteredClaims{
Issuer: registeredClaims.Issuer,
Subject: registeredClaims.Subject,
Audience: registeredClaims.Audience,
ID: registeredClaims.ID,
Expiry: numericDateToUnixTime(registeredClaims.Expiry),
NotBefore: numericDateToUnixTime(registeredClaims.NotBefore),
IssuedAt: numericDateToUnixTime(registeredClaims.IssuedAt),
},
CustomClaims: customClaims,
}
return validatedClaims, nil
}
could not get token claims: square/go-jose: unsupported key type/format)

Related

Mocking of API handler generated by swagger Golang

i really need some help to test the behaviour of my API, let me explain the context :
This API is written in go generated by swagger using the repository patern. In case of creating a new object i need to check if the name is not already exists in the database so i call repository's function to get Applications by name in the database (see below)
func (a *mongoApplicationRepository) GetApplicationByName(name string, ctx context.Context) (*models.Application, error) {
_, span := otel.Tracer("GetApplicationByName").Start(ctx, "GetApplicationByName")
defer span.End()
var application models.Application
err := a.mgConn.Collection("applications").
FindOne(context.TODO(), bson.M{"name": name}).Decode(&application)
if err != nil {
if err == mongo.ErrNoDocuments {
return &application, nil
}
return nil, err
}
return &application, nil
}
This function is called by the api handler that you can see bellow
type ApplicationCreateHandler struct {
API *operations.KubeesAPI
repo repo.ApplicationRepository
statsRepo repo.StatsRepository
}
func NewApplicationCreateHandler(API *operations.KubeesAPI, repo repo.ApplicationRepository, statsRepo repo.StatsRepository) ApplicationCreateHandler {
return ApplicationCreateHandler{
API: API,
repo: repo,
statsRepo: statsRepo,
}
}
// Handle is the HTTP handler for application creation
func (h *ApplicationCreateHandler) Handle(params application.AppCreateParams, principal *models.Principal) middleware.Responder {
traceName := "application-create"
ctx, span := otel.GetTracerProvider().Tracer(traceName).Start(context.TODO(), traceName)
defer span.End()
if params.Data == nil {
err := "unable to validate input"
logger().Errorln(err)
return application.NewAppCreateBadRequest().WithPayload(&models.APIResponse{
Msg: &err,
})
}
if err := params.Data.Validate(h.API.Formats()); err != nil {
err := fmt.Sprintf("unable to validate input: %v", err)
logger().Errorln(err)
return application.NewAppCreateBadRequest().WithPayload(&models.APIResponse{
Msg: &err,
})
}
app := models.Application{
ID: uuid.NewString(),
Name: params.Data.Name,
Selector: params.Data.Selector,
}
c, err := h.repo.GetApplicationByName(*params.Data.Name, ctx)
if err != nil {
err := fmt.Sprintf("Unable to get Application: %v", err)
logger().Errorln(err)
return application.NewAppCreateInternalServerError().WithPayload(&models.APIResponse{
Msg: &err,
})
}
if c.ID != "" {
r := "name already taken"
logger().Errorln(r)
return application.NewAppCreateInternalServerError().WithPayload(&models.APIResponse{
Msg: &r,
})
}
appDomain, err := app.ToDomainModel()
if err != nil {
err := fmt.Sprintf("Unable to convert application to domain model: %v", err)
logger().Errorln(err)
return application.NewAppCreateInternalServerError().WithPayload(&models.APIResponse{
Msg: &err,
})
}
err = h.repo.CreateApplication(appDomain, ctx)
if err != nil {
err := fmt.Sprintf("Unable to create Application: %v", err)
logger().Errorln(err)
return application.NewAppCreateInternalServerError().WithPayload(&models.APIResponse{
Msg: &err,
})
}
if err := h.statsRepo.UpdateApplicationsHistory(ctx); err != nil {
err := fmt.Sprintf("unable to update applications history: %v", err)
logger().Errorln(err)
return application.NewAppCreateInternalServerError().WithPayload(&models.APIResponse{
Msg: &err,
})
}
return application.NewAppCreateCreated()
}
I just want to check this behaviour and test in case we have already an application called the same as the new created one, which would raise an error and not in opposite case. But i don't know what to mock because the repository have some external dependencies
I would strongly suggest to make sure your ApplicationCreateHandler does only rely on interfaces. When that's the case you can mock the interfaces by writing a mock class, or generating on. You can test the ApplicationCreateHandlerby creating a new instance, and passing the mocked dependencies to it. Then execute theHandle()` method and ensure all dependencies are called.
I would strongly recommend generting your mock-classes. When you write your mocks yourself it's possible to introduce bugs in your test code. You wouldn't want that, right?
One great example of a mocking library is mockgen. You can easily instal it by following their github-readme.
Steps
Create interfaces for your dependencies.
It is best define the interface on the side that relies on the interface. So in you case that would be in the ApplicationCreateHandler file. The interfaces should reflect the needs of the handler.
type (
ApplicationRepo interface {
GetApplicationByName(name string, ctx context.Context)
CreateApplication(domain Domain, ctx context.Context)
}
// other dependencies here...
)
Writing a unit test
Create a new unit test
// youfile_test.go
func TestApplicationHandler(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockRepo := NewMockRepository(ctrl)
mockRepo.EXPECT().
Handle(gomock.any(), gomock.any()). // name, ctx
Return(nil, nil). // c, err
Once()
// other mocks...
// mockApi
// mockStatsRepo
h := NewApplicationHandler(mockApi, mockStats, mockRepo)
h.Handle(/*your test input*/)
// do checks
}
The test will throw an error if the mockRepo wasn't called exactly once.

ObjectIdFromHex invalid byte error on identical strings

I'm trying to implement a FindOne method in my Golang REST API. The trouble comes where i have to search by ID. I have to convert the ID into something readable by the database, so i use primitive.ObjectIDFromHex(id)
The problem is that this method throws an error :
2021/06/19 06:56:15 encoding/hex: invalid byte: U+000A
ONLY when i call it with the id that comes from my URL GET params.
I did two versions : one with hard-coded ID, and one with GET ID. See code below.
func Admin(id string) (bson.M, error) {
coll, err := db.ConnectToCollection("admin")
if err != nil {
log.Fatal(err)
}
var admin bson.M
HardCoded := "60cb275c074ab46a1aeda45e"
fmt.Println(HardCoded) // Just to be sure : the two strings seem identical
fmt.Println(id)
objetId, err := primitive.ObjectIDFromHex(id) // throws encoding error
// objetId, err := primitive.ObjectIDFromHex(HardCoded) // Doesnt throw encoding err
if err != nil {
log.Fatal(err)
}
var ctx = context.TODO()
if err := coll.FindOne(ctx, bson.M{"_id": objetId}).Decode(&admin); err != nil {
log.Fatal(err)
}
return admin, nil
}
Of course, you'll want to know where the param id comes from.
Here you go :
func GetAdmin(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
admin, err := Admin(params["id"]) // Calling the Admin function above
if err != nil {
fmt.Println(err)
http.Error(w, err.Error(), http.StatusUnauthorized)
} else {
JSON, err := json.Marshal(admin)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
w.Write(JSON)
}
}
Trim the line feed from the end of id:
id = strings.TrimSpace(id)
Use the %q format verb when debugging issues like this. The line feed is clearly visible in this output:
fmt.Printf("%q\n", HardCoded) // prints "60cb275c074ab46a1aeda45e"
fmt.Printf("%q\n", id) // prints "60cb275c074ab46a1aeda45e\n"

Golang SMTP error: 535 5.7.0 Invalid login or password

I'm trying to create emailing service with go.
When i tried to send email via gmail or office365 code works just fine but when i tried to send email via custom smtp i get "535 5.7.0 Invalid login or password" error.
I know username and password is correct because i am using same password and username with another python service with flask-mail and other services works just fine.
I don't have any documentation for custom smtp server but i know smtp server uses TLS
I tried plain auth, gomailer, smtp.SendMail() function and without startTLS but nothing changed.
here is my code;
func (m *Mail) sendMail(body, to, subject string) bool {
env := common.GetEnvironment()
mailServer := env.MailServer
mailUsername := env.MailUsername
SMTP := fmt.Sprintf("%s:%s", mailServer, env.MailPort)
auth := LoginAuth(mailUsername, env.MailPassword)
tlsconfig := &tls.Config{
ServerName: mailServer,
}
c, err := smtp.Dial(SMTP)
if err != nil {
zap.S().Error(err)
return false
}
c.StartTLS(tlsconfig)
if err = c.Auth(auth); err != nil {
zap.S().Error(err)
return false
}
if err = c.Mail(mailUsername); err != nil {
zap.S().Error(err)
return false
}
if err = c.Rcpt(to); err != nil {
zap.S().Error(err)
return false
}
w, err := c.Data()
if err != nil {
zap.S().Error(err)
return false
}
_, err = w.Write([]byte(body))
if err != nil {
zap.S().Error(err)
return false
}
err = w.Close()
if err != nil {
zap.S().Error(err)
return false
}
c.Quit()
return true
}
auth function;
import (
"errors"
"net/smtp"
)
type loginAuth struct {
username, password string
}
func LoginAuth(username, password string) smtp.Auth {
return &loginAuth{username, password}
}
func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
return "LOGIN", []byte(a.username), nil
}
func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
if more {
switch string(fromServer) {
case "Username:":
return []byte(a.username), nil
case "Password:":
return []byte(a.password), nil
default:
return nil, errors.New("unknown from server")
}
}
return nil, nil
}
Thank you for your helps
The error you get is definitely returned from smtp server. There are several authentication mechanisms supported by smtp protocol. If you do not know for sure which are supported by your server, you can debug it manually with the following command openssl s_client -crlf -ign_eof -connect <smtp_host>:<TLS_port>.
After sending EHLO to the server it will announce supported authentication mechanism(s). Then you can try to login manually and implement Start() and Next() properly.
Notice that some methods require login and password to be encoded(base64, md5, etc).
The command "AUTH LOGIN" does not expect a username argument.
Try the following instead and your authentication may work (if supported)
func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
return "LOGIN", nil, nil
}

How to fix: 403 Error with Google Cloud SQL Export

I am attempting to export a full SQL dump of one of our Cloud SQL Postgres instances to Google Cloud Storage so we can have more frequent backups using the google-api-go-client (https://github.com/googleapis/google-api-go-client)
Not matter what I configure, I keep getting this error: panic: googleapi: Error 403: The client is not authorized to make this request., notAuthorized from sqladminService.Instances.Export.
I have a service account configured with the following permissions:
Cloud SQL Admin
Storage Admin
Compute Storage Admin (for something else)
The bucket I am exporting to inherits permissions from the Storage Admin role.
Code:
./k8s/sql.go
package gcp
import (
"fmt"
"time"
"golang.org/x/net/context"
"golang.org/x/oauth2/google"
sqladmin "google.golang.org/api/sqladmin/v1beta4"
)
type SQLService interface {
Test(project string) error
}
type sqlService struct {
context context.Context
sqladminService *sqladmin.Service
}
func NewSQLService(serviceAccountJSON []byte) (SQLService, error) {
context := context.Background()
jwtCfg, err := google.JWTConfigFromJSON(serviceAccountJSON, sqladmin.SqlserviceAdminScope, sqladmin.CloudPlatformScope)
if err != nil {
return sqlService{}, err
}
httpClient := jwtCfg.Client(context)
sqladminService, err := sqladmin.New(httpClient)
if err != nil {
return sqlService{}, err
}
return sqlService{
context: context,
sqladminService: sqladminService,
}, nil
}
func (s sqlService) Test(project string) error {
instance := "REGION:INSTANCE_NAME
storageURI := fmt.Sprintf("gs://BUCKET/FILE-%s.sql.gz", time.Now().Format(time.RFC3339))
databases := []string{"DATABASE"}
req := &sqladmin.InstancesExportRequest{
ExportContext: &sqladmin.ExportContext{
Uri: storageURI,
Databases: databases,
},
}
_resp, err := s.sqladminService.Instances.Export(project, instance, req).Context(s.context).Do()
if err != nil {
return err
}
return nil
}
Test code:
func Test(cfg config.Config) {
sql, err := gcp.NewSQLService(cfg.GCPServiceAccountEncodedCreds)
if err != nil {
panic(err)
}
err = sql.Test(cfg.Project)
if err != nil {
panic(err)
}
}
Any help would be appreciated
The documentation for InstancesExport shows that the required parameters are the "projectId" and the "instanceId". You have declared instance as "REGION:INSTANCE_NAME" - but what you really want is "INSTANCE_NAME".
You aren't authorized to view that instance (because in this case, it doesn't exist).

Very Sporadic Go HTTP Error: multiple response.WriteHeader calls

I wrote Kanali which is an open source Kubernetes Ingress/API management tool and for about 1/200k requests I receive the following fatal error:
2017/08/16 12:40:57 http: multiple response.WriteHeader calls
{"level":"error","method":"GET","msg":"unknown error","time":"2017-08-16T12:40:57Z","uri":"/ommitted/path"}
{"level":"fatal","msg":"write tcp4 192.168.2.160:8443-\u003e192.168.4.0:54554: write: broken pipe","time":"2017-08-16T12:40:57Z"}
I'm having a really hard time reproducing it but here is the relevant code. Kanali is a large project but the td;lr is that after this first code snippet is executed, the second code snipped is executed which handles errors.
func (step WriteResponseStep) Do(ctx context.Context, m *metrics.Metrics, c *controller.Controller, w http.ResponseWriter, r *http.Request, resp *http.Response, trace opentracing.Span) error {
for k, v := range resp.Header {
for _, value := range v {
w.Header().Set(k, value)
}
}
closer, str, err := utils.DupReaderAndString(resp.Body)
if err != nil {
logrus.Errorf("error copying response body, response may not be as expected: %s", err.Error())
}
trace.SetTag("http.status_code", resp.StatusCode)
trace.SetTag("http.response_body", str)
w.WriteHeader(resp.StatusCode)
if _, err := io.Copy(w, closer); err != nil {
return err
}
return nil
}
later in the code...
if err != nil {
w.Header().Set("Content-Type", "application/json")
switch e := err.(type) {
case utils.Error:
logrus.WithFields(logrus.Fields{
"method": r.Method,
"uri": r.RequestURI,
}).Error(e.Error())
errStatus, err := json.Marshal(utils.JSONErr{Code: e.Status(), Msg: e.Error()})
if err != nil {
logrus.Warnf("could not marsah request headers into JSON - tracing data maybe not be as expected")
}
w.WriteHeader(e.Status())
if err := json.NewEncoder(w).Encode(utils.JSONErr{Code: e.Status(), Msg: e.Error()}); err != nil {
logrus.Fatal(err.Error())
}
default:
logrus.WithFields(logrus.Fields{
"method": r.Method,
"uri": r.RequestURI,
}).Error("unknown error")
errStatus, err := json.Marshal(utils.JSONErr{Code: http.StatusInternalServerError, Msg: "unknown error"})
if err != nil {
logrus.Warnf("could not marsah request headers into JSON - tracing data maybe not be as expected")
}
w.WriteHeader(http.StatusInternalServerError)
if err := json.NewEncoder(w).Encode(utils.JSONErr{Code: http.StatusInternalServerError, Msg: "unknown error"}); err != nil {
logrus.Fatal(err.Error())
}
}
}
The error message is telling you that WriteHeader is called more than once (either directly or indirectly by a call to Write). The header can only be written to the network once. Both snippets have a call to WriteHeader.