Skip to content

Commit

Permalink
licensing, mfa
Browse files Browse the repository at this point in the history
  • Loading branch information
wardviaene committed Oct 15, 2024
1 parent 2bcb11e commit 486df94
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 20 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Go test

on: [push]

jobs:
build:

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Go 1.23.x
uses: actions/setup-go@v5
with:
go-version: '1.23.x'
- name: Install dependencies
run: |
go get ./...
- name: Test
run: go test ./...
10 changes: 6 additions & 4 deletions auth/provisioning/scim/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import (
"github.com/in4it/go-devops-platform/users"
)

func New(storage storage.Iface, userStore *users.UserStore, token string) *scim {
func New(storage storage.Iface, userStore *users.UserStore, token string, disableFunc DisableFunc, reactivateFunc ReactivateFunc) *scim {
s := &scim{
Token: token,
UserStore: userStore,
storage: storage,
Token: token,
UserStore: userStore,
storage: storage,
DisableFunc: disableFunc,
ReactivateFunc: reactivateFunc,
}
return s
}
7 changes: 5 additions & 2 deletions auth/provisioning/scim/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import (
"github.com/in4it/go-devops-platform/users"
)

type DisableFunc func(storage.Iface, users.User) error
type ReactivateFunc func(storage.Iface, users.User) error

type scim struct {
Token string `json:"token"`
UserStore *users.UserStore `json:"userStore"`
storage storage.Iface
DisableFunc func(storage.Iface, users.User) error
ReactivateFunc func(storage.Iface, users.User) error
DisableFunc DisableFunc
ReactivateFunc ReactivateFunc
}

type Iface interface {
Expand Down
10 changes: 5 additions & 5 deletions auth/provisioning/scim/users_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestUsersGetCount100EmptyResult(t *testing.T) {
t.Fatalf("cannot empty user store")
}

s := New(storage, userStore, "token")
s := New(storage, userStore, "token", nil, nil)
req := httptest.NewRequest("GET", "http://example.com/api/scim/v2/Users?count=100&startIndex=1&", nil)
w := httptest.NewRecorder()
s.GetUsersHandler(w, req)
Expand Down Expand Up @@ -64,7 +64,7 @@ func TestUsersGetCount10(t *testing.T) {
if err != nil {
t.Fatalf("cannot create users: %s", err)
}
s := New(storage, userStore, "token")
s := New(storage, userStore, "token", nil, nil)
req := httptest.NewRequest("GET", "http://example.com/api/scim/v2/Users?count=10&startIndex=1&", nil)
w := httptest.NewRecorder()
s.GetUsersHandler(w, req)
Expand Down Expand Up @@ -104,7 +104,7 @@ func TestUsersGetCount10Start5(t *testing.T) {
if err != nil {
t.Fatalf("cannot create users: %s", err)
}
s := New(storage, userStore, "token")
s := New(storage, userStore, "token", nil, nil)
req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/api/scim/v2/Users?count=%d&startIndex=%d&", count, start), nil)
w := httptest.NewRecorder()
s.GetUsersHandler(w, req)
Expand Down Expand Up @@ -139,7 +139,7 @@ func TestUsersGetNonExistentUser(t *testing.T) {
t.Fatalf("cannot create new user stoer")
}

s := New(&memorystorage.MockMemoryStorage{}, userStore, "token")
s := New(&memorystorage.MockMemoryStorage{}, userStore, "token", nil, nil)
req := httptest.NewRequest("GET", "http://example.com/api/scim/v2/Users?filter=userName+eq+%22ward%40in4it.io%22&", nil)
w := httptest.NewRecorder()
s.GetUsersHandler(w, req)
Expand All @@ -166,7 +166,7 @@ func TestAddUser(t *testing.T) {
if err != nil {
t.Fatalf("cannot empty user store")
}
s := New(storage, userStore, "token")
s := New(storage, userStore, "token", nil, nil)
payload := PostUserRequest{
UserName: "[email protected]",
Name: Name{
Expand Down
2 changes: 1 addition & 1 deletion licensing/aws.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package license
package licensing

import (
"encoding/json"
Expand Down
2 changes: 1 addition & 1 deletion licensing/azure.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package license
package licensing

import (
"encoding/json"
Expand Down
2 changes: 1 addition & 1 deletion licensing/digitalocean.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package license
package licensing

import (
"bufio"
Expand Down
2 changes: 1 addition & 1 deletion licensing/gcp.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package license
package licensing

import (
"fmt"
Expand Down
2 changes: 1 addition & 1 deletion licensing/gcp_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package license
package licensing

import (
"crypto/sha256"
Expand Down
2 changes: 1 addition & 1 deletion licensing/license.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package license
package licensing

import (
"crypto/sha256"
Expand Down
2 changes: 1 addition & 1 deletion licensing/license_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package license
package licensing

import (
"crypto/sha256"
Expand Down
2 changes: 1 addition & 1 deletion licensing/nocloud.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package license
package licensing

import (
"fmt"
Expand Down
2 changes: 1 addition & 1 deletion licensing/types.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package license
package licensing

import "time"

Expand Down
62 changes: 62 additions & 0 deletions mfa/totp/verify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package totp

import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"encoding/base32"
"encoding/binary"
"fmt"
"strings"
"time"
)

const INTERVAL = 30

func GetToken(secret string, interval int64) (string, error) {
key, err := base32.StdEncoding.DecodeString(strings.ToUpper(secret))
if err != nil {
return "", fmt.Errorf("base32 decode error: %s", err)
}
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, uint64(interval))
hmacHash := hmac.New(sha1.New, key)
hmacHash.Write(buf)
h := hmacHash.Sum(nil)
offset := (h[19] & 15)

var header uint32
r := bytes.NewReader(h[offset : offset+4])
err = binary.Read(r, binary.BigEndian, &header)

if err != nil {
return "", fmt.Errorf("binary read error: %s", err)
}

return fmt.Sprintf("%06d", int((int(header)&0x7fffffff)%1000000)), nil
}

func Verify(secret, code string) (bool, error) {
token, err := GetToken(secret, time.Now().Unix()/30)
if err != nil {
return false, fmt.Errorf("GetToken error: %s", err)
}
return token == code, nil
}

func VerifyMultipleIntervals(secret, code string, count int) (bool, error) {
return verifyMultipleIntervals(secret, code, count, time.Now())
}

func verifyMultipleIntervals(secret, code string, count int, now time.Time) (bool, error) {
for i := 0; i < count; i++ {
token, err := GetToken(secret, now.Add(time.Duration(i)*time.Duration(-30)*time.Second).Unix()/30)
if err != nil {
return false, fmt.Errorf("GetToken error: %s", err)
}
if token == code {
return true, nil
}
}
return false, nil
}
49 changes: 49 additions & 0 deletions mfa/totp/verify_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package totp

import (
"testing"
"time"
)

func TestVerify(t *testing.T) { // validated with https://2fa.glitch.me/
interval := int64(57275699)
secret := "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"
token, err := GetToken(secret, interval)
if err != nil {
t.Fatalf("error: %s", err)
}
if token != "840823" {
t.Fatalf("wrong token. Got: %s", token)
}
}

func TestVerifyWrongSecret(t *testing.T) {
interval := int64(57275699)
secret := "wrong secret"
_, err := GetToken(secret, interval)
if err == nil {
t.Fatalf("expected error")
}
}

func TestVerifyMultipleIntervals(t *testing.T) {
secret := "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"
ok, err := verifyMultipleIntervals(secret, "312137", 20, time.Unix(1718272397, 0))
if err != nil {
t.Fatalf("error: %s", err)
}
if !ok {
t.Fatalf("no token matched")
}
}

func TestVerifyMultipleIntervalsWrongToken(t *testing.T) {
secret := "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"
ok, err := verifyMultipleIntervals(secret, "312137", 20, time.Unix(1718272000, 0))
if err != nil {
t.Fatalf("error: %s", err)
}
if ok {
t.Fatalf("token matched, but shouldn't have")
}
}

0 comments on commit 486df94

Please sign in to comment.