Merge remote-tracking branch 'origin/master' into feat-settings-ui

# Conflicts:
#	docs/package.json
#	docs/pnpm-lock.yaml
#	internal/configuration/validator/identity_providers_test.go
#	web/package.json
#	web/pnpm-lock.yaml
feat-otp-verification
James Elliott 2023-03-12 00:07:22 +11:00
commit 7ef1ba23df
No known key found for this signature in database
GPG Key ID: 0F1C4A096E857E49
14 changed files with 1078 additions and 911 deletions

View File

@ -15,7 +15,7 @@ RUN yarn global add pnpm && \
# =======================================
# ===== Build image for the backend =====
# =======================================
FROM golang:1.20.1-alpine AS builder-backend
FROM golang:1.20.2-alpine AS builder-backend
WORKDIR /go/src/app

View File

@ -13,7 +13,7 @@ RUN yarn install --frozen-lockfile && yarn build
# =======================================
# ===== Build image for the backend =====
# =======================================
FROM golang:1.20.1-alpine AS builder-backend
FROM golang:1.20.2-alpine AS builder-backend
WORKDIR /go/src/app

View File

@ -34,3 +34,20 @@ abide by:
- The available space is utilized efficiently in order to avoid scrolling where possible.
- The user only has to scroll in one direction to view available information. This direction should always be
vertically.
Recommendations on resolutions which are common:
- Desktop/Laptop:
1. 1920x1080
2. 1366x768
3. 2560x1440
4. 1280x720
- Tablet Devices (With Touch and Landscape):
1. 768x1024
2. 810x1080
3. 800x1280
- Mobile Devices (With Touch and Landscape):
1. 360x800
2. 390x844
3. 414x896
4. 412x915

View File

@ -3,8 +3,7 @@
"description": "Doks theme",
"version": "0.5.0",
"engines": {
"node": ">=16.18.1",
"pnpm": "7"
"node": ">=16.18.1"
},
"browserslist": [
"defaults"
@ -39,8 +38,8 @@
"version": "auto-changelog -p && git add CHANGELOG.md"
},
"devDependencies": {
"@babel/cli": "7.20.7",
"@babel/core": "7.20.12",
"@babel/cli": "7.21.0",
"@babel/core": "7.21.0",
"@babel/preset-env": "7.20.2",
"@fullhuman/postcss-purgecss": "5.0.0",
"@hyas/images": "0.3.2",
@ -50,7 +49,7 @@
"bootstrap": "5.2.3",
"bootstrap-icons": "1.10.3",
"clipboard": "2.0.11",
"eslint": "8.34.0",
"eslint": "8.35.0",
"exec-bin": "1.0.0",
"flexsearch": "0.7.31",
"highlight.js": "11.7.0",
@ -65,10 +64,10 @@
"postcss-cli": "10.1.0",
"purgecss-whitelister": "2.4.0",
"shx": "0.3.4",
"stylelint": "15.1.0",
"stylelint": "14.16.1",
"stylelint-config-standard-scss": "6.1.0"
},
"otherDependencies": {
"hugo": "0.110.0"
"hugo": "0.111.2"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -140,6 +140,20 @@ type PasswordDigest struct {
algorithm.Digest
}
// IsPlainText returns true if the underlying algorithm.Digest is a *plaintext.Digest.
func (d *PasswordDigest) IsPlainText() bool {
if d == nil || d.Digest == nil {
return false
}
switch d.Digest.(type) {
case *plaintext.Digest:
return true
default:
return false
}
}
// NewX509CertificateChain creates a new *X509CertificateChain from a given string, parsing each PEM block one by one.
func NewX509CertificateChain(in string) (chain *X509CertificateChain, err error) {
if in == "" {

View File

@ -160,6 +160,7 @@ const (
"an empty id"
errFmtOIDCClientInvalidSecret = "identity_providers: oidc: client '%s': option 'secret' is required"
errFmtOIDCClientInvalidSecretPlainText = "identity_providers: oidc: client '%s': option 'secret' is plaintext but it should be a hashed value as plaintext values are deprecated and will be removed when oidc becomes stable"
errFmtOIDCClientPublicInvalidSecret = "identity_providers: oidc: client '%s': option 'secret' is " +
"required to be empty when option 'public' is true"
errFmtOIDCClientRedirectURICantBeParsed = "identity_providers: oidc: client '%s': option 'redirect_uris' has an " +

View File

@ -166,6 +166,8 @@ func validateOIDCClients(config *schema.OpenIDConnectConfiguration, val *schema.
} else {
if client.Secret == nil {
val.Push(fmt.Errorf(errFmtOIDCClientInvalidSecret, client.ID))
} else if client.Secret.IsPlainText() {
val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidSecretPlainText, client.ID))
}
}

View File

@ -179,8 +179,8 @@ func TestShouldRaiseErrorWhenOIDCServerClientBadValues(t *testing.T) {
},
},
Errors: []string{
fmt.Sprintf(errFmtOIDCClientInvalidSecret, ""),
errFmtOIDCClientsWithEmptyID,
"identity_providers: oidc: client '': option 'secret' is required",
"identity_providers: oidc: one or more clients have been configured with an empty id",
},
},
{
@ -195,7 +195,7 @@ func TestShouldRaiseErrorWhenOIDCServerClientBadValues(t *testing.T) {
},
},
},
Errors: []string{fmt.Sprintf(errFmtOIDCClientInvalidPolicy, "client-1", "a-policy")},
Errors: []string{"identity_providers: oidc: client 'client-1': option 'policy' must be 'one_factor' or 'two_factor' but it is configured as 'a-policy'"},
},
{
Name: "ClientIDDuplicated",
@ -427,7 +427,7 @@ func TestShouldRaiseErrorWhenOIDCClientConfiguredWithBadGrantTypes(t *testing.T)
Clients: []schema.OpenIDConnectClientConfiguration{
{
ID: "good_id",
Secret: MustDecodeSecret("$plaintext$good_secret"),
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
Policy: "two_factor",
GrantTypes: []string{"bad_grant_type"},
RedirectURIs: []string{
@ -454,7 +454,7 @@ func TestShouldNotErrorOnCertificateValid(t *testing.T) {
Clients: []schema.OpenIDConnectClientConfiguration{
{
ID: "good_id",
Secret: MustDecodeSecret("$plaintext$good_secret"),
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
Policy: "two_factor",
RedirectURIs: []string{
"https://google.com/callback",
@ -480,7 +480,7 @@ func TestShouldRaiseErrorOnCertificateNotValid(t *testing.T) {
Clients: []schema.OpenIDConnectClientConfiguration{
{
ID: "good_id",
Secret: MustDecodeSecret("$plaintext$good_secret"),
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
Policy: "two_factor",
RedirectURIs: []string{
"https://google.com/callback",
@ -507,7 +507,7 @@ func TestShouldRaiseErrorOnKeySizeTooSmall(t *testing.T) {
Clients: []schema.OpenIDConnectClientConfiguration{
{
ID: "good_id",
Secret: MustDecodeSecret("$plaintext$good_secret"),
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
Policy: "two_factor",
RedirectURIs: []string{
"https://google.com/callback",
@ -587,7 +587,7 @@ func TestValidateIdentityProvidersShouldRaiseWarningOnSecurityIssue(t *testing.T
Clients: []schema.OpenIDConnectClientConfiguration{
{
ID: "good_id",
Secret: MustDecodeSecret("$plaintext$good_secret"),
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
Policy: "two_factor",
RedirectURIs: []string{
"https://google.com/callback",
@ -623,7 +623,7 @@ func TestValidateIdentityProvidersShouldRaiseErrorsOnInvalidClientTypes(t *testi
},
{
ID: "client-with-bad-redirect-uri",
Secret: MustDecodeSecret("$plaintext$a-secret"),
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
Public: false,
Policy: "two_factor",
RedirectURIs: []string{
@ -702,6 +702,33 @@ func TestValidateIdentityProvidersShouldNotRaiseErrorsOnValidClientOptions(t *te
assert.Len(t, validator.Warnings(), 0)
}
func TestValidateIdentityProvidersShouldRaiseWarningOnPlainTextClients(t *testing.T) {
validator := schema.NewStructValidator()
config := &schema.IdentityProvidersConfiguration{
OIDC: &schema.OpenIDConnectConfiguration{
HMACSecret: "hmac1",
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
Clients: []schema.OpenIDConnectClientConfiguration{
{
ID: "client-with-invalid-secret_standard",
Secret: MustDecodeSecret("$plaintext$a-secret"),
Policy: "two_factor",
RedirectURIs: []string{
"https://localhost",
},
},
},
},
}
ValidateIdentityProviders(config, validator)
assert.Len(t, validator.Errors(), 0)
require.Len(t, validator.Warnings(), 1)
assert.EqualError(t, validator.Warnings()[0], "identity_providers: oidc: client 'client-with-invalid-secret_standard': option 'secret' is plaintext but it should be a hashed value as plaintext values are deprecated and will be removed when oidc becomes stable")
}
func TestValidateIdentityProvidersShouldSetDefaultValues(t *testing.T) {
timeDay := time.Hour * 24
@ -713,7 +740,7 @@ func TestValidateIdentityProvidersShouldSetDefaultValues(t *testing.T) {
Clients: []schema.OpenIDConnectClientConfiguration{
{
ID: "a-client",
Secret: MustDecodeSecret("$plaintext$a-client-secret"),
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
RedirectURIs: []string{
"https://google.com",
},
@ -721,8 +748,8 @@ func TestValidateIdentityProvidersShouldSetDefaultValues(t *testing.T) {
},
{
ID: "b-client",
Description: "Normal DisplayName",
Secret: MustDecodeSecret("$plaintext$b-client-secret"),
Description: "Normal Description",
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
Policy: policyOneFactor,
UserinfoSigningAlgorithm: "RS256",
RedirectURIs: []string{
@ -745,7 +772,7 @@ func TestValidateIdentityProvidersShouldSetDefaultValues(t *testing.T) {
},
{
ID: "c-client",
Secret: MustDecodeSecret("$plaintext$a-client-secret"),
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
RedirectURIs: []string{
"https://google.com",
},
@ -753,7 +780,7 @@ func TestValidateIdentityProvidersShouldSetDefaultValues(t *testing.T) {
},
{
ID: "d-client",
Secret: MustDecodeSecret("$plaintext$a-client-secret"),
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
RedirectURIs: []string{
"https://google.com",
},
@ -761,7 +788,7 @@ func TestValidateIdentityProvidersShouldSetDefaultValues(t *testing.T) {
},
{
ID: "e-client",
Secret: MustDecodeSecret("$plaintext$a-client-secret"),
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
RedirectURIs: []string{
"https://google.com",
},
@ -1019,4 +1046,6 @@ AQmB98tdGLggbyXiODV2h+Rd37aFGb0QHzerIIsVNtMwlPCcp733D4kWJqTUYWZ+
KBL3XEahgs6Os5EYZ4aBAkEAjKE+2/nBYUdHVusjMXeNsE5rqwJND5zvYzmToG7+
xhv4RUAe4dHL4IDQoQRjhr3Nw+JYvtzBx0Iq/178xMnGKg==
-----END RSA PRIVATE KEY-----`
goodOpenIDConnectClientSecret = "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng" //nolint:gosec
)

View File

@ -1,4 +1,4 @@
FROM golang:1.20.1-alpine
FROM golang:1.20.2-alpine
ARG USER_ID
ARG GROUP_ID

View File

@ -1,4 +1,4 @@
FROM haproxy:2.7.3-alpine
FROM haproxy:2.7.4-alpine
USER root
RUN \

View File

@ -1,8 +1,8 @@
This email has been sent to you in order to validate your identity.
This email has been sent to you in order to validate your identity. Purpose: {{ .Title }}.
If you did not initiate the process your credentials might have been compromised and you should reset your password and contact an administrator.
To setup your 2FA please visit the following URL: {{ .LinkURL }}
To confirm your identity please visit the following URL: {{ .LinkURL }}
This email was generated by a user with the IP {{ .RemoteIP }}.

View File

@ -30,14 +30,14 @@
"@fortawesome/free-solid-svg-icons": "6.3.0",
"@fortawesome/react-fontawesome": "0.2.0",
"@mui/icons-material": "5.11.11",
"@mui/material": "5.11.11",
"@mui/styles": "5.11.11",
"@mui/material": "5.11.12",
"@mui/styles": "5.11.12",
"@simplewebauthn/browser": "7.1.0",
"@simplewebauthn/typescript-types": "7.0.0",
"axios": "1.3.4",
"broadcast-channel": "4.20.2",
"classnames": "2.3.2",
"i18next": "22.4.10",
"i18next": "22.4.11",
"i18next-browser-languagedetector": "7.0.1",
"i18next-http-backend": "2.1.1",
"qrcode.react": "3.1.0",
@ -45,7 +45,7 @@
"react-dom": "18.2.0",
"react-i18next": "12.2.0",
"react-loading": "2.0.3",
"react-router-dom": "6.8.2",
"react-router-dom": "6.9.0",
"react18-input-otp": "1.1.2",
"zxcvbn": "4.4.2"
},
@ -154,17 +154,17 @@
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "14.0.0",
"@types/jest": "29.4.0",
"@types/node": "18.14.6",
"@types/node": "18.15.0",
"@types/qrcode.react": "1.0.2",
"@types/react": "18.0.28",
"@types/react-dom": "18.0.11",
"@types/zxcvbn": "4.4.1",
"@typescript-eslint/eslint-plugin": "5.54.0",
"@typescript-eslint/parser": "5.54.0",
"@typescript-eslint/eslint-plugin": "5.54.1",
"@typescript-eslint/parser": "5.54.1",
"@vitejs/plugin-react": "3.1.0",
"esbuild": "0.17.11",
"esbuild-jest": "0.5.0",
"eslint": "8.35.0",
"eslint": "8.36.0",
"eslint-config-prettier": "8.7.0",
"eslint-config-react-app": "7.0.1",
"eslint-formatter-rdjson": "1.0.5",
@ -175,8 +175,8 @@
"eslint-plugin-react": "7.32.2",
"eslint-plugin-react-hooks": "4.6.0",
"husky": "8.0.3",
"jest": "29.4.3",
"jest-environment-jsdom": "29.4.3",
"jest": "29.5.0",
"jest-environment-jsdom": "29.5.0",
"jest-transform-stub": "2.0.0",
"jest-watch-typeahead": "2.2.2",
"prettier": "2.8.4",

File diff suppressed because it is too large Load Diff