Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ require (
github.com/jinzhu/copier v0.4.0
github.com/jmoiron/sqlx v1.4.0
github.com/joho/godotenv v1.5.1
github.com/korylprince/go-ad-auth/v3 v3.3.0
github.com/labstack/echo/v4 v4.13.3
github.com/lib/pq v1.10.9
github.com/mcnijman/go-emailaddress v1.1.1
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pressly/goose/v3 v3.24.1
github.com/stretchr/testify v1.10.0
github.com/xhit/go-simple-mail/v2 v2.16.0
go.uber.org/mock v0.5.0
golang.org/x/crypto v0.33.0
gopkg.in/guregu/null.v4 v4.0.0
)

Expand All @@ -37,6 +40,8 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/go-asn1-ber/asn1-ber v1.4.1 // indirect
github.com/go-ldap/ldap/v3 v3.1.7 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-test/deep v1.1.1 // indirect
Expand All @@ -57,7 +62,6 @@ require (
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.33.0 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
Expand Down
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-asn1-ber/asn1-ber v1.4.1 h1:qP/QDxOtmMoJVgXHCXNzDpA0+wkgYB2x5QoLMVOciyw=
github.com/go-asn1-ber/asn1-ber v1.4.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-ldap/ldap/v3 v3.1.7 h1:aHjuWTgZsnxjMgqzx0JHwNqz4jBYZTcNarbPFkW1Oww=
github.com/go-ldap/ldap/v3 v3.1.7/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
Expand Down Expand Up @@ -70,6 +75,8 @@ github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/korylprince/go-ad-auth/v3 v3.3.0 h1:iXuB+sCk4GniHnpUn0BAHH8rKeOLTKuYcBNvERa773Y=
github.com/korylprince/go-ad-auth/v3 v3.3.0/go.mod h1:19M0geaOeNN489k1MO6GCqOCgbruYRQkHRBfhhUZAoE=
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
Expand All @@ -88,6 +95,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mcnijman/go-emailaddress v1.1.1 h1:AGhgVDG3tCDaL0/Vc6erlPQjDuDN3dAT7rRdgFtetr0=
github.com/mcnijman/go-emailaddress v1.1.1/go.mod h1:5whZrhS8Xp5LxO8zOD35BC+b76kROtsh+dPomeRt/II=
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
Expand Down Expand Up @@ -143,6 +152,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
Expand All @@ -157,10 +167,12 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b h1:FQtJ1MxbXoIIrZHZ33M+w5+dAP9o86rgpjoKr/ZmT7k=
Expand Down
20 changes: 20 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ func main() {
}
log.Printf("Connected to CDN: %s", cdnConfig.Endpoint)

adPort, err := strconv.Atoi(os.Getenv("WAUTH_AD_PORT"))
if err != nil {
log.Fatalf("failed to get ad port env: %+v", err)
}

adSecurity, err := strconv.Atoi(os.Getenv("WAUTH_AD_SECURITY"))
if err != nil {
log.Fatalf("failed to get ad security env: %+v", err)
}

// Generate config
conf := &views.Config{
Version: Version,
Expand All @@ -115,6 +125,16 @@ func main() {
AuthenticationKey: os.Getenv("WAUTH_AUTHENTICATION_KEY"),
SigningKey: signingKey,
},
AD: views.ADConfig{
Server: os.Getenv("WAUTH_AD_SERVER"),
Port: adPort,
BaseDN: os.Getenv("WAUTH_AD_BASE_DN"),
Security: adSecurity,
Bind: views.ADBind{
Username: os.Getenv("WAUTH_AD_BIND_USERNAME"),
Password: os.Getenv("WAUTH_AD_BIND_PASSWORD"),
},
},
}

v := views.New(conf, dbHost, cdn)
Expand Down
9 changes: 9 additions & 0 deletions utils/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"math/big"

whirl "github.com/balacode/zr-whirl"
"golang.org/x/crypto/scrypt"
)

type (
Expand Down Expand Up @@ -50,6 +51,14 @@ func HashPass(password string) string {
return next
}

func HashPassScrypt(password, salt []byte) (string, error) {
hash, err := scrypt.Key(password, salt, 32768, 16, 2, 64)
if err != nil {
return "", fmt.Errorf("failed to generate hash: %w", err)
}
return hex.EncodeToString(hash), nil
}

func GenerateRandomLength(length int, randomType Type) (string, error) {
if length < 6 || length > 40 {
return "", errors.New("length must be between 6 and 40")
Expand Down
41 changes: 41 additions & 0 deletions views/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,47 @@ func (v *Views) SetTokenHandler(c echo.Context) error {
return c.JSON(http.StatusInternalServerError, data)
}

/*
_ = tokenByte

callback := ""
callbackURL, err := url.Parse(c.QueryParam("callback"))
fmt.Println(callbackURL.String(), err)
if err == nil && strings.HasSuffix(callbackURL.Host, v.conf.BaseDomainName) && callbackURL.String() != "" {
callback = callbackURL.String()
}
// c.Response().Header().Set("Content-Type", "application/json")
c.Response().Header().Set("Authorization", "Bearer "+tokenString)
cookie := new(http.Cookie)
cookie.Name = "token"
cookie.Expires = time.Now().Add(30 * time.Second)
cookie.Value = tokenString
cookie.Secure = false
cookie.HttpOnly = false
cookie.Domain = "localhost"
c.SetCookie(cookie)
http.SetCookie(c.Response().Writer, cookie)
c.Response().Committed = false
// c.Response().Write(tokenByte)
// _, err = c.Response().Write(tokenByte)
// if err != nil {
// log.Printf("failed to write token to http body: %+v", err)
// data := struct {
// Error error `json:"error"`
// }{
// Error: fmt.Errorf("failed to write token to http body: %w", err),
// }
// return c.JSON(http.StatusInternalServerError, data)
// }
if len(callback) > 0 {
// c.Response().Header().Set("Location", callback)
// c.Response().WriteHeader(http.StatusFound)
return c.Redirect(http.StatusFound, callback+"?token="+tokenString)
// c.Redirect()
}
return nil
*/

c.Response().Header().Set("Content-Type", "application/json")
c.Response().WriteHeader(http.StatusCreated)

Expand Down
85 changes: 85 additions & 0 deletions views/login.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package views

import (
"errors"
"fmt"
"log"
"net/http"
"net/mail"
"net/url"
"strings"

"github.com/go-ldap/ldap/v3"
"github.com/google/uuid"
auth "github.com/korylprince/go-ad-auth/v3"
"github.com/labstack/echo/v4"
emailParser "github.com/mcnijman/go-emailaddress"
"github.com/patrickmn/go-cache"
"gopkg.in/guregu/null.v4"

Expand Down Expand Up @@ -76,6 +81,23 @@ func (v *Views) _loginPost(c echo.Context) error {
// Authentication
u, resetPw, err := v.user.VerifyUser(c.Request().Context(), u)
if err != nil {
address, _ := emailParser.Parse(username)
if address != nil {
u.LDAPUsername = null.StringFrom(address.LocalPart)
ldapUser, err := v.user.GetUser(c.Request().Context(), u)
if err != nil {
return fmt.Errorf("failed to get user ldap: %w", err)
}
if !ldapUser.LDAPUsername.Valid {
return errors.New("failed to get user LDAP username")
}
valid, err := v.LDAPFunc(ldapUser.LDAPUsername.String, password)
if err != nil {
return fmt.Errorf("failed to call LDAP function: %w", err)
}

fmt.Println("LDAP: ", valid)
}
log.Printf("failed login for \"%s\": %v", u.Username, err)

err = session.Save(c.Request(), c.Response())
Expand Down Expand Up @@ -147,3 +169,66 @@ func (v *Views) _loginPost(c echo.Context) error {

return c.Redirect(http.StatusFound, callback)
}

func (v *Views) LDAPFunc(username, password string) (bool, error) {
config := &auth.Config{
Server: v.conf.AD.Server,
Port: v.conf.AD.Port,
BaseDN: v.conf.AD.BaseDN,
Security: auth.SecurityType(v.conf.AD.Security),
}

conn, err := config.Connect()
if err != nil {
return false, echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("error connecting to server: %w", err))
}
defer conn.Conn.Close()

status, err := conn.Bind(v.conf.AD.Bind.Username, v.conf.AD.Bind.Password)
if err != nil {
return false, echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("error binding to server: %w", err))
}

if !status {
return false, echo.NewHTTPError(http.StatusInternalServerError, errors.New("error binding to server: invalid credentials"))
}

status1, err := auth.Authenticate(config, username, password)
if err != nil {
return false, echo.NewHTTPError(http.StatusUnauthorized, fmt.Errorf("unable to authenticate %s with error: %w", username, err))
}

if status1 {
var entry *ldap.Entry
if _, err = mail.ParseAddress(username); err == nil {
entry, err = conn.GetAttributes("userPrincipalName", username, []string{"memberOf"})
} else {
entry, err = conn.GetAttributes("samAccountName", username, []string{"memberOf"})
}
if err != nil {
return false, echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("error getting user groups: %w", err))
}

dnGroups := entry.GetAttributeValues("memberOf")

if len(dnGroups) == 0 {
return false, echo.NewHTTPError(http.StatusUnauthorized, errors.New("BIND_SAM user not member of any groups"))
}

// stv := false

for _, group := range dnGroups {
if group == "CN=STV Admin,CN=Users,DC=ystv,DC=local" {
// stv = true
return true, nil
}
}

// if !stv {
// return false, echo.NewHTTPError(http.StatusUnauthorized, fmt.Errorf("STV not allowed for %s!\n", username))
// }
log.Printf("%s is authenticated", username)
return true, nil
}
return false, echo.NewHTTPError(http.StatusUnauthorized, fmt.Errorf("user not authenticated: %s", username))
}
14 changes: 14 additions & 0 deletions views/views.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ type (
CDNEndpoint string
Mail SMTPConfig
Security SecurityConfig
AD ADConfig
}

ADConfig struct {
Server string
Port int
BaseDN string
Security int
Bind ADBind
}

ADBind struct {
Username string
Password string
}

// SMTPConfig stores the SMTP Mailer configuration
Expand Down