initial commit
This commit is contained in:
37
Dockerfile
Normal file
37
Dockerfile
Normal file
@@ -0,0 +1,37 @@
|
||||
# ---- Build Stage ----
|
||||
FROM golang:1.26 AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# ---- Step 1: Copy go.mod/go.sum for caching ----
|
||||
# Copy only the minimal files first for layer caching
|
||||
COPY libshared/go.mod libshared/go.sum ./libshared/
|
||||
COPY role-manager/go.mod role-manager/go.sum ./role-manager/
|
||||
|
||||
# ---- Step 2: Download dependencies ----
|
||||
RUN go -C libshared mod download
|
||||
RUN go -C role-manager mod download
|
||||
|
||||
# ---- Step 3: Copy full source code ----
|
||||
COPY libshared ./libshared
|
||||
COPY role-manager ./role-manager
|
||||
|
||||
# ---- Step 4: Create Go workspace inside container ----
|
||||
RUN go work init ./role-manager ./libshared
|
||||
|
||||
## Optional: verify workspace
|
||||
#RUN go work list
|
||||
|
||||
# ---- Step 5: Build binary ----
|
||||
WORKDIR /app/role-manager
|
||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o server
|
||||
|
||||
# ---- Runtime Stage ----
|
||||
FROM gcr.io/distroless/base-debian12
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/role-manager/server .
|
||||
|
||||
EXPOSE 8080
|
||||
USER nonroot:nonroot
|
||||
ENTRYPOINT ["/app/server"]
|
||||
170
assume-role.go
Normal file
170
assume-role.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"libshared"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
/*
|
||||
* Returns a temporary token with the permissions of the specified role.
|
||||
*/
|
||||
|
||||
type AssumeRoleRequest struct {
|
||||
Rolename string `json:"rolename"`
|
||||
}
|
||||
|
||||
type AssumeRoleResponse struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func assumeRole(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
log.Println("Assume Role Request")
|
||||
|
||||
var response APIResponse[string]
|
||||
|
||||
// Only allow POST
|
||||
if r.Method != http.MethodPost {
|
||||
|
||||
response.Timestamp = time.Now().Unix()
|
||||
response.Status = "error"
|
||||
response.Message = "HTTP POST method not allowed"
|
||||
//response.Response: "Testing"
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
json.NewEncoder(w).Encode(response)
|
||||
return
|
||||
}
|
||||
|
||||
// Get JWT from Authorization header
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
if authHeader == "" {
|
||||
|
||||
response.Timestamp = time.Now().Unix()
|
||||
response.Status = "error"
|
||||
response.Message = "HTTP POST method not allowed"
|
||||
//response.Response: "Testing"
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
json.NewEncoder(w).Encode(response)
|
||||
return
|
||||
}
|
||||
|
||||
parts := strings.SplitN(authHeader, " ", 2)
|
||||
|
||||
if len(parts) != 2 || parts[0] != "Bearer" {
|
||||
fmt.Println("Invalid Authorization header format")
|
||||
http.Error(w, "Invalid Authorization format", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
tokenString := parts[1]
|
||||
|
||||
// Replace with your actual secret or keyfunc
|
||||
secret := []byte("super-secret-key")
|
||||
|
||||
claims := &MyClaims{}
|
||||
|
||||
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
// Validate signing method if needed
|
||||
return secret, nil
|
||||
})
|
||||
|
||||
if err != nil || !token.Valid {
|
||||
fmt.Println("Invalid token:", err)
|
||||
http.Error(w, "Invalid token", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// Access parsed values
|
||||
log.Println("sub:", claims.Sub)
|
||||
log.Println("purpose:", claims.Purpose)
|
||||
log.Println("account:", claims.Account)
|
||||
// exp and iat come from RegisteredClaims
|
||||
log.Println("exp:", claims.ExpiresAt)
|
||||
log.Println("iat:", claims.IssuedAt)
|
||||
|
||||
if claims.ExpiresAt == nil || time.Now().After(claims.ExpiresAt.Time) {
|
||||
log.Println("Token expired")
|
||||
http.Error(w, "Token expired", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// Read the raw request body
|
||||
body, err := io.ReadAll(r.Body)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Failed to read body:", err)
|
||||
http.Error(w, "Failed to read body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
defer r.Body.Close()
|
||||
|
||||
// Parse JSON into Role struct
|
||||
var role AssumeRoleRequest
|
||||
if err := json.Unmarshal(body, &role); err != nil {
|
||||
log.Println("Invalid JSON:", err)
|
||||
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if role.Rolename == "" {
|
||||
log.Println("Rolename is required")
|
||||
http.Error(w, "Rolename is required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Print the parsed values to terminal
|
||||
log.Println("Rolename:", role.Rolename)
|
||||
|
||||
// Prevent duplication of roles with the same name for the same account
|
||||
|
||||
checkExisting := pool.QueryRow(context.Background(),
|
||||
"SELECT id FROM roles WHERE accountid = $1 AND rolename = $2",
|
||||
claims.Account, role.Rolename)
|
||||
|
||||
var existingRoleID int64
|
||||
err = checkExisting.Scan(&existingRoleID)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Role does not exist", err)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Role ID", existingRoleID)
|
||||
|
||||
roleToken, err := createJWT(secret, claims.Account, role.Rolename)
|
||||
if err != nil {
|
||||
log.Println("Error creating JWT:", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(roleToken)
|
||||
|
||||
apiresponse := libshared.APIResponse[AssumeRoleResponse]{}
|
||||
apiresponse.Timestamp = time.Now().Unix()
|
||||
apiresponse.Status = "success"
|
||||
apiresponse.Message = "Role assumed successfully"
|
||||
apiresponse.Content = AssumeRoleResponse{Token: roleToken}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(apiresponse)
|
||||
|
||||
// w.Write([]byte("JWT parsed successfully"))
|
||||
|
||||
}
|
||||
16
attach-role.go
Normal file
16
attach-role.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func attachRole(w http.ResponseWriter, r *http.Request) {
|
||||
log.Println("attachRole called")
|
||||
|
||||
}
|
||||
|
||||
func detachRole(w http.ResponseWriter, r *http.Request) {
|
||||
log.Println("detachRole called")
|
||||
|
||||
}
|
||||
150
create-role.go
Normal file
150
create-role.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
type APIResponse[T any] struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Status string `json:"status"` // "success" or "fail"
|
||||
Message string `json:"message"`
|
||||
Response T `json:"response"`
|
||||
}
|
||||
|
||||
// Custom claims struct
|
||||
type MyClaims struct {
|
||||
Sub string `json:"sub"`
|
||||
Purpose string `json:"purpose"`
|
||||
Account string `json:"account"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
type RoleCreateType struct {
|
||||
Rolename string `json:"rolename"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func createRole(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var response APIResponse[string]
|
||||
|
||||
// Only allow POST
|
||||
if r.Method != http.MethodPost {
|
||||
|
||||
response.Timestamp = time.Now().Unix()
|
||||
response.Status = "error"
|
||||
response.Message = "HTTP POST method not allowed"
|
||||
//response.Response: "Testing"
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
json.NewEncoder(w).Encode(response)
|
||||
return
|
||||
}
|
||||
|
||||
// Get JWT from Authorization header
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
if authHeader == "" {
|
||||
|
||||
response.Timestamp = time.Now().Unix()
|
||||
response.Status = "error"
|
||||
response.Message = "HTTP POST method not allowed"
|
||||
//response.Response: "Testing"
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
json.NewEncoder(w).Encode(response)
|
||||
return
|
||||
}
|
||||
|
||||
parts := strings.SplitN(authHeader, " ", 2)
|
||||
if len(parts) != 2 || parts[0] != "Bearer" {
|
||||
http.Error(w, "Invalid Authorization format", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
tokenString := parts[1]
|
||||
|
||||
// Replace with your actual secret or keyfunc
|
||||
secret := []byte("super-secret-key")
|
||||
|
||||
claims := &MyClaims{}
|
||||
|
||||
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
// Validate signing method if needed
|
||||
return secret, nil
|
||||
})
|
||||
|
||||
if err != nil || !token.Valid {
|
||||
http.Error(w, "Invalid token", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// Access parsed values
|
||||
log.Println("sub:", claims.Sub)
|
||||
log.Println("purpose:", claims.Purpose)
|
||||
log.Println("account:", claims.Account)
|
||||
// exp and iat come from RegisteredClaims
|
||||
log.Println("exp:", claims.ExpiresAt)
|
||||
log.Println("iat:", claims.IssuedAt)
|
||||
|
||||
if claims.ExpiresAt == nil || time.Now().After(claims.ExpiresAt.Time) {
|
||||
http.Error(w, "Token expired", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// Read the raw request body
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to read body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
// Parse JSON into Role struct
|
||||
var role RoleCreateType
|
||||
if err := json.Unmarshal(body, &role); err != nil {
|
||||
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if role.Rolename == "" {
|
||||
http.Error(w, "Rolename is required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Print the parsed values to terminal
|
||||
log.Println("Rolename:", role.Rolename)
|
||||
log.Println("Description:", role.Description)
|
||||
|
||||
// Prevent duplication of roles with the same name for the same account
|
||||
checkExisting := pool.QueryRow(context.Background(),
|
||||
"SELECT FROM roles WHERE accountid = $1 AND rolename = $2",
|
||||
claims.Account, role.Rolename)
|
||||
err = checkExisting.Scan()
|
||||
if err == nil {
|
||||
log.Println("Already exists")
|
||||
w.WriteHeader(http.StatusConflict)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = pool.Exec(
|
||||
context.Background(),
|
||||
"INSERT INTO roles (accountid, rolename, description) VALUES ($1, $2, $3)",
|
||||
claims.Account, role.Rolename, role.Description)
|
||||
if err != nil {
|
||||
log.Println("Error inserting role into database:", err)
|
||||
http.Error(w, "Failed to create role", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write([]byte("JWT parsed successfully"))
|
||||
}
|
||||
38
db.go
Normal file
38
db.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
var pool *pgxpool.Pool
|
||||
|
||||
func getDbPool() *pgxpool.Pool {
|
||||
// Construct the connection string
|
||||
// Note: Ensure your Docker Compose env vars match these keys!
|
||||
dburl := fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=disable",
|
||||
os.Getenv("POSTGRES_USER"),
|
||||
os.Getenv("POSTGRES_PASSWORD"),
|
||||
os.Getenv("POSTGRES_HOSTNAME"),
|
||||
os.Getenv("POSTGRES_DB"),
|
||||
)
|
||||
|
||||
var err error
|
||||
// Use pgxpool.New instead of Connect for v5
|
||||
pool, err = pgxpool.New(context.Background(), dburl)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to create connection pool: %v", err)
|
||||
}
|
||||
|
||||
// Ping the database to verify the connection is actually live
|
||||
err = pool.Ping(context.Background())
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to ping database: %v", err)
|
||||
}
|
||||
|
||||
return pool
|
||||
}
|
||||
111
get-role-token.go
Normal file
111
get-role-token.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
type getRoleTokenRequest struct {
|
||||
RoleName string `json:"rolename"`
|
||||
}
|
||||
|
||||
func getRoleToken(w http.ResponseWriter, r *http.Request) {
|
||||
log.Println("getRoleToken called")
|
||||
|
||||
// Only allow POST
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// Get JWT from Authorization header
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
if authHeader == "" {
|
||||
http.Error(w, "Missing Authorization header", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
parts := strings.SplitN(authHeader, " ", 2)
|
||||
if len(parts) != 2 || parts[0] != "Bearer" {
|
||||
http.Error(w, "Invalid Authorization format", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
tokenString := parts[1]
|
||||
|
||||
// Replace with your actual secret or keyfunc
|
||||
secret := []byte("super-secret-key")
|
||||
|
||||
claims := &MyClaims{}
|
||||
|
||||
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
// Validate signing method if needed
|
||||
return secret, nil
|
||||
})
|
||||
|
||||
if err != nil || !token.Valid {
|
||||
http.Error(w, "Invalid token", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// Access parsed values
|
||||
log.Println("sub:", claims.Sub)
|
||||
log.Println("purpose:", claims.Purpose)
|
||||
log.Println("account:", claims.Account)
|
||||
// exp and iat come from RegisteredClaims
|
||||
log.Println("exp:", claims.ExpiresAt)
|
||||
log.Println("iat:", claims.IssuedAt)
|
||||
|
||||
if claims.ExpiresAt == nil || time.Now().After(claims.ExpiresAt.Time) {
|
||||
http.Error(w, "Token expired", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("Add in validation that the user is allowed to get this token")
|
||||
|
||||
// Read the raw request body
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to read body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
// Parse JSON into Role struct
|
||||
var role getRoleTokenRequest
|
||||
if err := json.Unmarshal(body, &role); err != nil {
|
||||
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("Received request for role:", role.RoleName)
|
||||
|
||||
log.Println("Authentication would taken place here")
|
||||
|
||||
// Check if policy with the same name already exists for the account
|
||||
checkExisting := pool.QueryRow(context.Background(),
|
||||
"SELECT FROM roles WHERE accountid = $1 AND rolename = $2",
|
||||
claims.Account, role.RoleName)
|
||||
log.Println("checkExisting:", role.RoleName)
|
||||
err = checkExisting.Scan()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusConflict)
|
||||
return
|
||||
}
|
||||
|
||||
usertoken, err := createJWT(secret, claims.Account, role.RoleName)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println(usertoken)
|
||||
|
||||
}
|
||||
16
go.mod
Normal file
16
go.mod
Normal file
@@ -0,0 +1,16 @@
|
||||
module role-manager
|
||||
|
||||
go 1.25.0
|
||||
|
||||
require (
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
github.com/jackc/pgx/v5 v5.9.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
)
|
||||
28
go.sum
Normal file
28
go.sum
Normal file
@@ -0,0 +1,28 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.9.1 h1:uwrxJXBnx76nyISkhr33kQLlUqjv7et7b9FjCen/tdc=
|
||||
github.com/jackc/pgx/v5 v5.9.1/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
22
jwt.go
Normal file
22
jwt.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
// CreateJWT generates a signed JWT
|
||||
func createJWT(secret []byte, account string, role string) (string, error) {
|
||||
claims := jwt.MapClaims{
|
||||
"sub": role, // subject (user id)
|
||||
"exp": time.Now().Add(time.Hour).Unix(), // expiration
|
||||
"iat": time.Now().Unix(), // issued at
|
||||
"purpose": "role",
|
||||
"account": account,
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
|
||||
return token.SignedString(secret)
|
||||
}
|
||||
23
main.go
Normal file
23
main.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
pool = getDbPool()
|
||||
|
||||
http.HandleFunc("/role/create-role", createRole)
|
||||
http.HandleFunc("/role/attach-role", attachRole)
|
||||
http.HandleFunc("/role/detach-role", detachRole)
|
||||
http.HandleFunc("/role/assume-role", assumeRole)
|
||||
http.HandleFunc("/role/get-role-token", getRoleToken)
|
||||
//http.HandleFunc("/role/authorize-role", authorizeRole)
|
||||
|
||||
log.Println("server running on :8080")
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
Reference in New Issue
Block a user