Skip to content
This repository has been archived by the owner on Dec 13, 2024. It is now read-only.

Commit

Permalink
Merge pull request #32 from p-society/auth/rbac
Browse files Browse the repository at this point in the history
feat/fix: adds rbac
  • Loading branch information
zakhaev26 authored Feb 24, 2024
2 parents 17b6c8e + fe441ae commit e8bc33d
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 57 deletions.
28 changes: 8 additions & 20 deletions auth/internal/handlers/callback_signup.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,16 @@ import (
"net/http"
"strings"

"github.com/p-society/gc-server/auth/internal"
"github.com/p-society/gc-server/auth/internal/db"
"github.com/p-society/gc-server/auth/internal/utils"
"github.com/p-society/gc-server/auth/pkg/security"
model "github.com/p-society/gc-server/schemas/pkg/models"
)

func CallbackVerification(w http.ResponseWriter, r *http.Request) {

var (
p model.Player
pv *model.ValidationSchema
p *model.Player
reqBody struct {
OTP int `json:"otp"`
}
Expand All @@ -26,43 +25,32 @@ func CallbackVerification(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")

if authHeader == "" && strings.Split(authHeader, " ")[0] != "Bearer" {
r.Header.Set("Content-Type", "application/json")
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"error": "Authorization Token Not found",
})
return
}

token := strings.Split(authHeader, " ")[1]
pv = security.ParseAccessToken(token)
p = security.ParseAccessToken(token)

if err := pv.Valid(); err != nil {
r.Header.Set("Content-Type", "application/json")
if err := p.Valid(); err != nil {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"error": err.Error(),
})
return
}

if err := internal.CheckOTP(pv.OTP, reqBody.OTP); err != nil {
r.Header.Set("Content-Type", "application/json")
if err := utils.CheckOTP(p.OTP, reqBody.OTP); err != nil {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"error": err.Error(),
})
return
}

p = model.Player{
FirstName: pv.FirstName,
LastName: pv.LastName,
Role: pv.Role,
Email: pv.Email,
Branch: pv.Branch,
Year: pv.Branch,
ContactNo: pv.ContactNo,
Social: pv.Social,
}

res, _ := db.PlayerCollection.InsertOne(context.TODO(), p)

json.NewEncoder(w).Encode(res.InsertedID)
Expand Down
67 changes: 67 additions & 0 deletions auth/internal/handlers/login_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package handlers

import (
"context"
"encoding/json"
"net/http"
"time"

"github.com/golang-jwt/jwt"
"github.com/p-society/gc-server/auth/internal/db"
"github.com/p-society/gc-server/auth/pkg/security"
model "github.com/p-society/gc-server/schemas/pkg/models"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"golang.org/x/crypto/bcrypt"
)

func Login(w http.ResponseWriter, r *http.Request) {
var (
p model.Player
reqBody struct {
Mail string `json:"mail"`
Password string `json:"password"`
}
)
w.Header().Set("Content-Type", "application/json")

if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil {
json.NewEncoder(w).Encode(map[string]interface{}{
"error": err.Error(),
})
}

filter := bson.M{
"email": reqBody.Mail,
}

err := db.PlayerCollection.FindOne(context.TODO(), filter).Decode(&p)
if err == mongo.ErrNoDocuments {
json.NewEncoder(w).Encode(map[string]interface{}{
"error": err.Error(),
})
return
}

err = bcrypt.CompareHashAndPassword([]byte(p.Password), []byte(reqBody.Password))
if err != nil {
json.NewEncoder(w).Encode(map[string]interface{}{
"error": err.Error(),
})
return
}

p.StandardClaims = jwt.StandardClaims{
IssuedAt: time.Now().Unix(),
ExpiresAt: time.Now().Add(time.Minute * 60 * 24 * 12).Unix(),
}

token, err := security.NewAccessToken(p)
if err != nil {
panic(err)
}

json.NewEncoder(w).Encode(map[string]interface{}{
"accessToken": token,
})
}
30 changes: 19 additions & 11 deletions auth/internal/handlers/signup_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@ import (
"time"

"github.com/golang-jwt/jwt"
"github.com/p-society/gc-server/auth/internal"
"github.com/p-society/gc-server/auth/internal/utils"
"github.com/p-society/gc-server/auth/pkg/security"
model "github.com/p-society/gc-server/schemas/pkg/models"
"golang.org/x/crypto/bcrypt"
)

func SignUpHandler(w http.ResponseWriter, r *http.Request) {
var pv model.ValidationSchema
var p model.Player

err := json.NewDecoder(r.Body).Decode(&pv)
w.Header().Set("Content-Type", "application/json")
err := json.NewDecoder(r.Body).Decode(&p)
defer r.Body.Close()

if err != nil {
json.NewEncoder(w).Encode(err)
return
}
err = pv.Valid()
err = p.Valid()

if err != nil {
json.NewEncoder(w).Encode(map[string]interface{}{
Expand All @@ -31,10 +33,9 @@ func SignUpHandler(w http.ResponseWriter, r *http.Request) {
return
}

fmt.Println("pv.Email @signup", pv.Email)
err = internal.IsUniqueInDB(pv.Email)
fmt.Println("p.Email @signup", p.Email)
err = utils.IsUniqueInDB(p.Email)
if err != nil {
r.Header.Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"error": err.Error(),
})
Expand All @@ -43,14 +44,21 @@ func SignUpHandler(w http.ResponseWriter, r *http.Request) {

// TODO:Send OTP Mail

pv.StandardClaims = jwt.StandardClaims{
p.StandardClaims = jwt.StandardClaims{
IssuedAt: time.Now().Unix(),
ExpiresAt: time.Now().Add(5 * time.Minute).Unix(),
}
// TODO : Check password to be
p.OTP = utils.GenerateOTP(6)
fmt.Println(p.OTP)
hashedPass, err := bcrypt.GenerateFromPassword([]byte(p.Password), 10)
if err != nil {
panic(err)
}

p.Password = string(hashedPass)

pv.OTP = internal.GenerateOTP(6)
fmt.Println("uhTP : ", pv.OTP)
token, err := security.NewAccessToken(pv)
token, err := security.NewAccessToken(p)
if err != nil {
json.NewEncoder(w).Encode(map[string]interface{}{
"error": err.Error(),
Expand Down
1 change: 1 addition & 0 deletions auth/internal/router/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ func AuthRouter() *mux.Router {

r.HandleFunc("/v0/auth/signup", handlers.SignUpHandler).Methods("post")
r.HandleFunc("/v0/auth/callback/signup", handlers.CallbackVerification).Methods("post")
r.HandleFunc("/v0/auth/login", handlers.Login).Methods("POST")
return r
}
17 changes: 17 additions & 0 deletions auth/internal/utils/extract_token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package utils

import (
"fmt"
"net/http"
"strings"
)

func ExtractTokenFromHeader(r *http.Request) (string, error) {

authHeader := r.Header.Get("Authorization")
if authHeader == "" && strings.Split(authHeader, " ")[0] == "Bearer" {
return "", fmt.Errorf("token not found")
}

return strings.Split(authHeader, " ")[1], nil
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package utils

import (
"fmt"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package utils

import (
"context"
Expand Down
9 changes: 4 additions & 5 deletions auth/pkg/security/jwt_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ import (
model "github.com/p-society/gc-server/schemas/pkg/models"
)

func NewAccessToken(claims model.ValidationSchema) (string, error) {
func NewAccessToken(claims model.Player) (string, error) {
accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

return accessToken.SignedString([]byte("saswat,tu23kranklekeiiitkyunaaya"))
}

func ParseAccessToken(accessToken string) *model.ValidationSchema {
parsedAccessToken, _ := jwt.ParseWithClaims(accessToken, &model.ValidationSchema{}, func(token *jwt.Token) (interface{}, error) {
func ParseAccessToken(accessToken string) *model.Player {
parsedAccessToken, _ := jwt.ParseWithClaims(accessToken, &model.Player{}, func(token *jwt.Token) (interface{}, error) {
return []byte([]byte("saswat,tu23kranklekeiiitkyunaaya")), nil
})
return parsedAccessToken.Claims.(*model.ValidationSchema)
return parsedAccessToken.Claims.(*model.Player)
}
50 changes: 50 additions & 0 deletions auth/pkg/security/rbac.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package security

import (
"net/http"

"github.com/p-society/gc-server/auth/internal/utils"
)

// RoleGuard is a middleware for role-based access control
type RoleGuard struct {
AllowedRoles []string
Handler http.Handler
}

// ServeHTTP implements the http.Handler interface for RoleGuard
func (rg *RoleGuard) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var (
token string
err error
)

token, err = utils.ExtractTokenFromHeader(r)
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
return
}

p := ParseAccessToken(token)

// Check if user's role is allowed
if !contains(rg.AllowedRoles, p.Role) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusForbidden)
return
}

// Call the next handler in the chain
rg.Handler.ServeHTTP(w, r)
}

// contains checks if a string is present in a slice of strings
func contains(roles []string, role string) bool {
for _, r := range roles {
if r == role {
return true
}
}
return false
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
require (
github.com/golang-jwt/jwt v3.2.2+incompatible
go.mongodb.org/mongo-driver v1.14.0
golang.org/x/crypto v0.19.0
)

require (
Expand All @@ -21,7 +22,6 @@ require (
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/text v0.14.0 // indirect
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
Expand Down
18 changes: 2 additions & 16 deletions schemas/pkg/models/user_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,17 @@ type Player struct {
FirstName string `json:"firstName" bson:"firstName"`
LastName string `json:"lastName" bson:"lastName"`
Email string `json:"email" bson:"email"`
Password string `json:"password" bson:"password"`
Role string `json:"role" bson:"role"`
Branch string `json:"branch" bson:"branch"`
Year string `json:"year" bson:"year"`
ContactNo string `json:"contactNo" bson:"contactNo"`
Social []string `json:"socials,omitempty" bson:"socials,omitempty"`
}

type ValidationSchema struct {
ID primitive.ObjectID `json:"_id,omitempty"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
Email string `json:"email"`
Role string `json:"role"`
Branch string `json:"branch"`
Year string `json:"year"`
ContactNo string `json:"contactNo"`
Social []string `json:"socials,omitempty"`
OTP int `json:"otp"`
jwt.StandardClaims
}


func ValidateRole(p *Player) error {

for _, role := range enum.Roles {
Expand Down Expand Up @@ -83,7 +73,3 @@ func ValidatePlayer(p Player) error {

return nil
}

func (p Player) Valid() error {
return ValidatePlayer(p)
}

0 comments on commit e8bc33d

Please sign in to comment.