in the beginning, there was darkness
This commit is contained in:
commit
308e237fc6
|
@ -0,0 +1,47 @@
|
|||
#+title: MCIAS
|
||||
#+created: <2025-05-09 Fri 13:42>
|
||||
|
||||
* MCIAS
|
||||
|
||||
MCIAS is the metacircular identity and access system.
|
||||
|
||||
It currently provides the following across metacircular services:
|
||||
|
||||
1. User password authentication.
|
||||
2. User token authentication.
|
||||
3. Database credential authentication.
|
||||
|
||||
Future work should consider adding support for:
|
||||
1. TOTP
|
||||
2. Policy management.
|
||||
|
||||
** API endpoints
|
||||
|
||||
*** The login type
|
||||
|
||||
The general datastructure used to log in should look like:
|
||||
|
||||
#+begin_src: json
|
||||
{
|
||||
"version": "v1",
|
||||
"login": {
|
||||
"user": "username",
|
||||
"password": "secret password",
|
||||
"token": "1234567890",
|
||||
"totp": "123456"
|
||||
}
|
||||
}
|
||||
#+end_src
|
||||
|
||||
Any fields that aren't used should be omitted. The =version= and
|
||||
=login.user= types are required, as well as the appropriate
|
||||
credential field.
|
||||
|
||||
*** =/v1/login/password=
|
||||
|
||||
The request should be a JSON object:
|
||||
|
||||
|
||||
*** =/v1/login/token=
|
||||
|
||||
*** =/v1/credentials/database=
|
|
@ -0,0 +1,13 @@
|
|||
package data
|
||||
|
||||
const saltLength = 32
|
||||
|
||||
func Salt() ([]byte, error) {
|
||||
salt := make([]byte, saltLength)
|
||||
_, err := rand.Read(salt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return salt, nil
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package data
|
||||
|
||||
const (
|
||||
scryptN = 32768
|
||||
scriptR = 8
|
||||
scryptP = 1
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID string
|
||||
Created int64
|
||||
User string
|
||||
Password []byte
|
||||
Salt []byte
|
||||
}
|
||||
|
||||
type Login struct {
|
||||
User string `json:"user"`
|
||||
Password string `json:"password,omitzero"`
|
||||
Token string `json:"token,omitzero"`
|
||||
}
|
||||
|
||||
func derive(password string, salt []byte) []byte {
|
||||
return scrypt.Key(login.Password, u.Salt, scryptN, scryptR, scryptN, 32)
|
||||
}
|
||||
|
||||
func (u *User) Check(login *Login) bool {
|
||||
if u.User != login.User {
|
||||
return false
|
||||
}
|
||||
|
||||
derived := derive(login.Password, u.Salt)
|
||||
|
||||
if subtle.ConstantTimeCompare(derived, u.Password) != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (u *User) Register(login *Login) error {
|
||||
var err error
|
||||
|
||||
if u.User != "" && u.User != login.User {
|
||||
return errors.New("invalid user")
|
||||
}
|
||||
|
||||
if u.ID == "" {
|
||||
u.ID = ulid.Make()
|
||||
}
|
||||
|
||||
u.User = login.User
|
||||
u.Salt, err = Salt()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to register user: %w", err)
|
||||
}
|
||||
|
||||
u.Password = derive(login.Password, u.Salt)
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
module git.wntrmute.dev/kyle/mcias
|
||||
|
||||
go 1.23.8
|
||||
|
||||
require github.com/oklog/ulid/v2 v2.1.0 // indirect
|
|
@ -0,0 +1,3 @@
|
|||
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
|
||||
github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
|
||||
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
|
|
@ -0,0 +1,29 @@
|
|||
CREATE TABLE users (
|
||||
id text primary key,
|
||||
created integer,
|
||||
user text not null,
|
||||
password blob not null,
|
||||
salt blob not null
|
||||
);
|
||||
|
||||
CREATE TABLE tokens (
|
||||
id text primary key,
|
||||
uid text not null,
|
||||
token text not null,
|
||||
expires integer default 0,
|
||||
FOREIGN KEY(uid) REFERENCES user(id)
|
||||
);
|
||||
|
||||
CREATE TABLE database (
|
||||
id text primary key,
|
||||
host text not null,
|
||||
port integer default 5432,
|
||||
name text not null,
|
||||
user text not null,
|
||||
password text not null
|
||||
);
|
||||
|
||||
CREATE TABLE registrations (
|
||||
id text primary key,
|
||||
code text not null
|
||||
);
|
Loading…
Reference in New Issue