Skip to content

Commit

Permalink
RBAC done using google cloud authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
PeanutBrrutter committed Jul 7, 2024
1 parent 56d52fd commit 33a203f
Show file tree
Hide file tree
Showing 12 changed files with 270 additions and 157 deletions.
Binary file modified EduSync.exe
Binary file not shown.
96 changes: 0 additions & 96 deletions auth.go

This file was deleted.

108 changes: 108 additions & 0 deletions authHandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package main

import (
"encoding/json"
"fmt"
"html/template"
"log"
"net/http"

"github.com/gorilla/mux"
"github.com/gorilla/sessions"
"github.com/markbates/goth"
"github.com/markbates/goth/gothic"
"github.com/markbates/goth/providers/google"
)

func AuthHandler(router *mux.Router, config *Config) {
maxAge := 86400 * 30 // 30 days
isProd := true // Set to true when serving over https

store := sessions.NewCookieStore([]byte(config.SessionSecret))
store.MaxAge(maxAge)
store.Options.Path = "/"
store.Options.HttpOnly = true // HttpOnly should always be enabled
store.Options.Secure = isProd

gothic.Store = store
goth.UseProviders(google.New(config.GoogleClientID, config.GoogleClientSecret, "https://localhost:8080/auth/google/callback", "email", "profile"))

router.HandleFunc("/auth/{provider}/callback", func(res http.ResponseWriter, req *http.Request) {
user, err := gothic.CompleteUserAuth(res, req)
if err != nil {
fmt.Fprintln(res, err)
return
}

userObj, userRole, err := getUserRole(user.Email)
if err != nil {
fmt.Fprintln(res, err)
return
}
log.Println("User role:", userRole)

// Only store the user object into the session if userRole is not an empty string
if userRole != "" {
// Create a User object with the user role
currentUser := User{
GoogleID: user.UserID,
Name: user.Name,
Email: user.Email,
ContactNumber: userObj.ContactNumber, // Use contact number from the retrieved user object
Role: userObj.Role,
CreatedAt: userObj.CreatedAt,
UpdatedAt: userObj.UpdatedAt,
}

// Serialize the user object to JSON
userData, err := json.Marshal(currentUser)
if err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
return
}

// Get the session and store the user data
session, err := store.Get(req, "auth-session")
if err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
return
}
session.Values["user"] = userData
err = session.Save(req, res)
if err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
return
}

// Redirect based on user role
if userRole == "Admin" {
AdminHandler(router)
http.Redirect(res, req, "/admin", http.StatusFound)
} else if userRole == "Instructor" {
InstructorHandler(router)
http.Redirect(res, req, "/instructor", http.StatusFound)
} else if userRole == "Student" {
StudentHandler(router)
http.Redirect(res, req, "/student", http.StatusFound)
} else if userRole == "Parent" {
ParentHandler(router)
http.Redirect(res, req, "/parent", http.StatusFound)
}
} else {
http.Redirect(res, req, "/unregistered", http.StatusFound)
}
}).Methods("GET")

router.HandleFunc("/auth/{provider}", func(res http.ResponseWriter, req *http.Request) {
gothic.BeginAuthHandler(res, req)
}).Methods("GET")

router.HandleFunc("/login", func(res http.ResponseWriter, req *http.Request) {
t, err := template.ParseFiles("templates/login.html")
if err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
return
}
t.Execute(res, false)
}).Methods("GET")
}
97 changes: 48 additions & 49 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,65 +6,22 @@ import (
"fmt"
"log"
"net/http"
"os"
"strings"

"github.com/joho/godotenv"

firebase "firebase.google.com/go"
"firebase.google.com/go/db"
"google.golang.org/api/option"
"github.com/gorilla/sessions"
)

// Use godot package to load/read the .env file and
// return the value of the key (for local env)
func goDotEnvVariable(key string) string {

// load .env file
err := godotenv.Load(".env")

if err != nil {
log.Fatalf("Error loading .env file")
}

return os.Getenv(key)
}

// Initialize Firebase client
var (
firebaseClient *db.Client
firebaseApp *firebase.App
)

// InitializeFirebase initializes the Firebase app and sets the global firebaseClient variable
func initializeFirebase() error {
ctx := context.Background()

// databaseURL, found := os.LookupEnv("DATABASE_URL")
// if !found {
// log.Fatalf("DATABASE_URL is not set in the environment variables")
// }

databaseURL := goDotEnvVariable("DATABASE_URL")
if databaseURL == "" {
return fmt.Errorf("DATABASE_URL is not set in the environment variables")
}

conf := &firebase.Config{DatabaseURL: databaseURL}

//opt := option.WithCredentialsFile("edusync-7bd5e-firebase-adminsdk-x49uh-af084a6314.json")
opt := option.WithCredentialsFile("edusync-test-firebase-adminsdk-hk5kl-9af0162b09.json")

firebaseApp, err := firebase.NewApp(ctx, conf, opt)
if err != nil {
return fmt.Errorf("error initializing firebase app: %v", err)
}
var firebaseClient *db.Client
var store = sessions.NewCookieStore([]byte("1L6x-SPtG8-EqJUkR7htTJx-5K4rt-ZTKeh-rxPw-AM="))

client, err := firebaseApp.Database(ctx)
func initDB(app *firebase.App) error {
// Initialize Firebase client
client, err := app.Database(context.Background())
if err != nil {
return fmt.Errorf("error creating firebase DB client: %v", err)
}

firebaseClient = client
return nil
}
Expand Down Expand Up @@ -154,6 +111,48 @@ func isParentChildInClass(currentUser User, students []Student, class Class) boo
return false
}

func getUserRole(email string) (User, string, error) {
ctx := context.Background()
var user User
var userRole string

// Check if firebaseClient is initialized
if firebaseClient == nil {
log.Println("Firebase client is not initialized")
return user, userRole, fmt.Errorf("firebase client is not initialized")
}

// Map categories to Firebase references
categoryRefs := map[string]string{
"Student": "/students",
"Parent": "/parents",
"Instructor": "/instructors",
"Admin": "/admins",
}

// Iterate through each category and check if the email exists
for category, ref := range categoryRefs {
categoryRef := firebaseClient.NewRef(ref)
dataSnapshot, err := categoryRef.OrderByChild("email").EqualTo(email).GetOrdered(ctx)
if err != nil {
log.Printf("Error fetching data from %s: %v", category, err)
continue
}

// Check if dataSnapshot has any children
if len(dataSnapshot) > 0 {
userRole = category
// Assuming dataSnapshot[0] is the first match and it contains the user data
if err := dataSnapshot[0].Unmarshal(&user); err != nil {
log.Printf("Error unmarshalling data for %s: %v", category, err)
continue
}
break
}
}
return user, userRole, nil
}

// CRUD operations with role checks

// Student CRUD
Expand Down
2 changes: 1 addition & 1 deletion database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ var students = []Student{
User: User{
GoogleID: "test-student",
Name: "John Doe",
Email: "johndoe_student@example.com",
Email: "jeyvianangjieen@gmail.com",
ContactNumber: "91234567",
Role: "Student",
},
Expand Down
60 changes: 60 additions & 0 deletions firebase.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main

import (
"context"
"fmt"
"log"
"os"

//"github.com/joho/godotenv"

firebase "firebase.google.com/go"
"google.golang.org/api/option"
)

// Use godot package to load/read the .env file and
// return the value of the key (for local env)
// func goDotEnvVariable(key string) string {

// // load .env file
// err := godotenv.Load(".env")

// if err != nil {
// log.Fatalf("Error loading .env file")
// }

// return os.Getenv(key)
// }

// InitializeFirebase initializes the Firebase app and sets the global firebaseClient variable
func initializeFirebase() error {
ctx := context.Background()

databaseURL, found := os.LookupEnv("DATABASE_URL")
if !found {
log.Fatalf("DATABASE_URL is not set in the environment variables")
}

// databaseURL := goDotEnvVariable("DATABASE_URL")
// if databaseURL == "" {
// return fmt.Errorf("DATABASE_URL is not set in the environment variables")
// }

conf := &firebase.Config{DatabaseURL: databaseURL}

opt := option.WithCredentialsFile("edusync-7bd5e-firebase-adminsdk-x49uh-af084a6314.json")
//opt := option.WithCredentialsFile("edusync-test-firebase-adminsdk-hk5kl-9af0162b09.json")

app, err := firebase.NewApp(ctx, conf, opt)
if err != nil {
return fmt.Errorf("error initializing firebase app: %v", err)
}

var firebaseApp = app

err = initDB(firebaseApp)
if err != nil {
return fmt.Errorf("error initializing database: %v", err)
}
return nil
}
Loading

0 comments on commit 33a203f

Please sign in to comment.