Compare commits
10 Commits
feat/add-j
...
0.13.1
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5bf26f7385 | ||
![]() |
1b269dc6db | ||
![]() |
ce9a115a14 | ||
![]() |
f2f4c72aa6 | ||
![]() |
9970eb16c9 | ||
![]() |
23e53286bd | ||
![]() |
47acff05e2 | ||
![]() |
5572928619 | ||
![]() |
85b4cd6339 | ||
![]() |
f0d38ab260 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -10,4 +10,5 @@ build
|
|||||||
data.db
|
data.db
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.env.local
|
.env.local
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
|
.vscode/
|
@@ -7,7 +7,7 @@
|
|||||||
Authorizer
|
Authorizer
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
**Authorizer** is an open-source authentication and authorization solution for your applications. Bring your database and have complete control over the user information. You can self-host authorizer instances and connect to any database (Currently supports [Postgres](https://www.postgresql.org/), [MySQL](https://www.mysql.com/), [SQLite](https://www.sqlite.org/index.html), [SQLServer](https://www.microsoft.com/en-us/sql-server/), [MongoDB](https://mongodb.com/),[ArangoDB](https://www.arangodb.com/)).
|
**Authorizer** is an open-source authentication and authorization solution for your applications. Bring your database and have complete control over the user information. You can self-host authorizer instances and connect to any database (Currently supports [Postgres](https://www.postgresql.org/), [MySQL](https://www.mysql.com/), [SQLite](https://www.sqlite.org/index.html), [SQLServer](https://www.microsoft.com/en-us/sql-server/), [MongoDB](https://mongodb.com/), [ArangoDB](https://www.arangodb.com/)).
|
||||||
|
|
||||||
## Table of contents
|
## Table of contents
|
||||||
|
|
||||||
|
@@ -259,17 +259,6 @@ const InputField = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (Object.values(SelectInputType).includes(inputType)) {
|
if (Object.values(SelectInputType).includes(inputType)) {
|
||||||
if (inputType === SelectInputType.JWT_TYPE) {
|
|
||||||
return (
|
|
||||||
<Select size="sm" {...props}>
|
|
||||||
{[variables[inputType]].map((value: string) => (
|
|
||||||
<option value="value" key={value}>
|
|
||||||
{value}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const { options, ...rest } = props;
|
const { options, ...rest } = props;
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
@@ -293,10 +282,18 @@ const InputField = ({
|
|||||||
<Textarea
|
<Textarea
|
||||||
{...props}
|
{...props}
|
||||||
size="lg"
|
size="lg"
|
||||||
value={inputData[inputType]}
|
fontSize={14}
|
||||||
onChange={(e: any) => {
|
value={variables[inputType] ? variables[inputType] : ''}
|
||||||
setInputData({ ...inputData, [inputType]: e.target.value });
|
onChange={(
|
||||||
}}
|
event: Event & {
|
||||||
|
target: HTMLInputElement;
|
||||||
|
}
|
||||||
|
) =>
|
||||||
|
setVariables({
|
||||||
|
...variables,
|
||||||
|
[inputType]: event.target.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -49,6 +49,8 @@ export const SelectInputType = {
|
|||||||
|
|
||||||
export const TextAreaInputType = {
|
export const TextAreaInputType = {
|
||||||
CUSTOM_ACCESS_TOKEN_SCRIPT: 'CUSTOM_ACCESS_TOKEN_SCRIPT',
|
CUSTOM_ACCESS_TOKEN_SCRIPT: 'CUSTOM_ACCESS_TOKEN_SCRIPT',
|
||||||
|
JWT_PRIVATE_KEY: 'JWT_PRIVATE_KEY',
|
||||||
|
JWT_PUBLIC_KEY: 'JWT_PUBLIC_KEY',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SwitchInputType = {
|
export const SwitchInputType = {
|
||||||
@@ -66,3 +68,21 @@ export const ArrayInputOperations = {
|
|||||||
APPEND: 'APPEND',
|
APPEND: 'APPEND',
|
||||||
REMOVE: 'REMOVE',
|
REMOVE: 'REMOVE',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const HMACEncryptionType = {
|
||||||
|
HS256: 'HS256',
|
||||||
|
HS384: 'HS384',
|
||||||
|
HS512: 'HS512',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RSAEncryptionType = {
|
||||||
|
RS256: 'RS256',
|
||||||
|
RS384: 'RS384',
|
||||||
|
RS512: 'RS512',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ECDSAEncryptionType = {
|
||||||
|
ES256: 'ES256',
|
||||||
|
ES384: 'ES384',
|
||||||
|
ES512: 'ES512',
|
||||||
|
};
|
||||||
|
@@ -21,6 +21,8 @@ export const EnvVariablesQuery = `
|
|||||||
JWT_TYPE,
|
JWT_TYPE,
|
||||||
JWT_SECRET,
|
JWT_SECRET,
|
||||||
JWT_ROLE_CLAIM,
|
JWT_ROLE_CLAIM,
|
||||||
|
JWT_PRIVATE_KEY,
|
||||||
|
JWT_PUBLIC_KEY,
|
||||||
REDIS_URL,
|
REDIS_URL,
|
||||||
SMTP_HOST,
|
SMTP_HOST,
|
||||||
SMTP_PORT,
|
SMTP_PORT,
|
||||||
|
@@ -31,6 +31,9 @@ import {
|
|||||||
TextInputType,
|
TextInputType,
|
||||||
TextAreaInputType,
|
TextAreaInputType,
|
||||||
SwitchInputType,
|
SwitchInputType,
|
||||||
|
HMACEncryptionType,
|
||||||
|
RSAEncryptionType,
|
||||||
|
ECDSAEncryptionType,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
import { UpdateEnvVariables } from '../graphql/mutation';
|
import { UpdateEnvVariables } from '../graphql/mutation';
|
||||||
import { getObjectDiff, capitalizeFirstLetter } from '../utils';
|
import { getObjectDiff, capitalizeFirstLetter } from '../utils';
|
||||||
@@ -48,6 +51,8 @@ interface envVarTypes {
|
|||||||
JWT_TYPE: string;
|
JWT_TYPE: string;
|
||||||
JWT_SECRET: string;
|
JWT_SECRET: string;
|
||||||
JWT_ROLE_CLAIM: string;
|
JWT_ROLE_CLAIM: string;
|
||||||
|
JWT_PRIVATE_KEY: string;
|
||||||
|
JWT_PUBLIC_KEY: string;
|
||||||
REDIS_URL: string;
|
REDIS_URL: string;
|
||||||
SMTP_HOST: string;
|
SMTP_HOST: string;
|
||||||
SMTP_PORT: string;
|
SMTP_PORT: string;
|
||||||
@@ -92,6 +97,8 @@ export default function Environment() {
|
|||||||
JWT_TYPE: '',
|
JWT_TYPE: '',
|
||||||
JWT_SECRET: '',
|
JWT_SECRET: '',
|
||||||
JWT_ROLE_CLAIM: '',
|
JWT_ROLE_CLAIM: '',
|
||||||
|
JWT_PRIVATE_KEY: '',
|
||||||
|
JWT_PUBLIC_KEY: '',
|
||||||
REDIS_URL: '',
|
REDIS_URL: '',
|
||||||
SMTP_HOST: '',
|
SMTP_HOST: '',
|
||||||
SMTP_PORT: '',
|
SMTP_PORT: '',
|
||||||
@@ -177,7 +184,6 @@ export default function Environment() {
|
|||||||
const {
|
const {
|
||||||
data: { _env: envData },
|
data: { _env: envData },
|
||||||
} = await client.query(EnvVariablesQuery).toPromise();
|
} = await client.query(EnvVariablesQuery).toPromise();
|
||||||
|
|
||||||
const diff = getObjectDiff(envVariables, envData);
|
const diff = getObjectDiff(envVariables, envData);
|
||||||
const updatedEnvVariables = diff.reduce(
|
const updatedEnvVariables = diff.reduce(
|
||||||
(acc: any, property: string) => ({
|
(acc: any, property: string) => ({
|
||||||
@@ -374,39 +380,67 @@ export default function Environment() {
|
|||||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||||
<Text fontSize="sm">JWT Type:</Text>
|
<Text fontSize="sm">JWT Type:</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Center w="70%">
|
<Flex w="70%">
|
||||||
<Flex w="100%" justifyContent="space-between">
|
|
||||||
<Flex flex="2">
|
|
||||||
<InputField
|
|
||||||
variables={envVariables}
|
|
||||||
setVariables={setEnvVariables}
|
|
||||||
inputType={SelectInputType.JWT_TYPE}
|
|
||||||
isDisabled={true}
|
|
||||||
defaultValue={SelectInputType.JWT_TYPE}
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
<Flex flex="3" justifyContent="center" alignItems="center">
|
|
||||||
<Text fontSize="sm">
|
|
||||||
More JWT types will be enabled in upcoming releases.
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
</Center>
|
|
||||||
</Flex>
|
|
||||||
<Flex>
|
|
||||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
|
||||||
<Text fontSize="sm">JWT Secret</Text>
|
|
||||||
</Flex>
|
|
||||||
<Center w="70%">
|
|
||||||
<InputField
|
<InputField
|
||||||
variables={envVariables}
|
variables={envVariables}
|
||||||
setVariables={setEnvVariables}
|
setVariables={setEnvVariables}
|
||||||
fieldVisibility={fieldVisibility}
|
inputType={SelectInputType.JWT_TYPE}
|
||||||
setFieldVisibility={setFieldVisibility}
|
value={SelectInputType.JWT_TYPE}
|
||||||
inputType={HiddenInputType.JWT_SECRET}
|
options={{
|
||||||
|
...HMACEncryptionType,
|
||||||
|
...RSAEncryptionType,
|
||||||
|
...ECDSAEncryptionType,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
{Object.values(HMACEncryptionType).includes(envVariables.JWT_TYPE) ? (
|
||||||
|
<Flex>
|
||||||
|
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||||
|
<Text fontSize="sm">JWT Secret</Text>
|
||||||
|
</Flex>
|
||||||
|
<Center w="70%">
|
||||||
|
<InputField
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setEnvVariables}
|
||||||
|
fieldVisibility={fieldVisibility}
|
||||||
|
setFieldVisibility={setFieldVisibility}
|
||||||
|
inputType={HiddenInputType.JWT_SECRET}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Flex>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Flex>
|
||||||
|
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||||
|
<Text fontSize="sm">Public Key</Text>
|
||||||
|
</Flex>
|
||||||
|
<Center w="70%">
|
||||||
|
<InputField
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setEnvVariables}
|
||||||
|
inputType={TextAreaInputType.JWT_PUBLIC_KEY}
|
||||||
|
placeholder="Add public key here"
|
||||||
|
minH="25vh"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Flex>
|
||||||
|
<Flex>
|
||||||
|
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||||
|
<Text fontSize="sm">Private Key</Text>
|
||||||
|
</Flex>
|
||||||
|
<Center w="70%">
|
||||||
|
<InputField
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setEnvVariables}
|
||||||
|
inputType={TextAreaInputType.JWT_PRIVATE_KEY}
|
||||||
|
placeholder="Add private key here"
|
||||||
|
minH="25vh"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Flex>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<Flex>
|
<Flex>
|
||||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||||
<Text fontSize="sm">JWT Role Claim:</Text>
|
<Text fontSize="sm">JWT Role Claim:</Text>
|
||||||
|
@@ -15,4 +15,6 @@ const (
|
|||||||
DbTypeMongodb = "mongodb"
|
DbTypeMongodb = "mongodb"
|
||||||
// DbTypeYugabyte is the yugabyte database type
|
// DbTypeYugabyte is the yugabyte database type
|
||||||
DbTypeYugabyte = "yugabyte"
|
DbTypeYugabyte = "yugabyte"
|
||||||
|
// DbTypeMariaDB is the mariadb database type
|
||||||
|
DbTypeMariaDB = "mariadb"
|
||||||
)
|
)
|
||||||
|
@@ -44,16 +44,12 @@ func NewProvider() (*provider, error) {
|
|||||||
switch envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) {
|
switch envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) {
|
||||||
case constants.DbTypePostgres, constants.DbTypeYugabyte:
|
case constants.DbTypePostgres, constants.DbTypeYugabyte:
|
||||||
sqlDB, err = gorm.Open(postgres.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
|
sqlDB, err = gorm.Open(postgres.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
|
||||||
break
|
|
||||||
case constants.DbTypeSqlite:
|
case constants.DbTypeSqlite:
|
||||||
sqlDB, err = gorm.Open(sqlite.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
|
sqlDB, err = gorm.Open(sqlite.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
|
||||||
break
|
case constants.DbTypeMysql, constants.DbTypeMariaDB:
|
||||||
case constants.DbTypeMysql:
|
|
||||||
sqlDB, err = gorm.Open(mysql.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
|
sqlDB, err = gorm.Open(mysql.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
|
||||||
break
|
|
||||||
case constants.DbTypeSqlserver:
|
case constants.DbTypeSqlserver:
|
||||||
sqlDB, err = gorm.Open(sqlserver.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
|
sqlDB, err = gorm.Open(sqlserver.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
4
server/env/env.go
vendored
4
server/env/env.go
vendored
@@ -118,6 +118,10 @@ func InitEnv() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if envData.StringEnv[constants.EnvKeyCustomAccessTokenScript] == "" {
|
||||||
|
envData.StringEnv[constants.EnvKeyCustomAccessTokenScript] = os.Getenv(constants.EnvKeyCustomAccessTokenScript)
|
||||||
|
}
|
||||||
|
|
||||||
if envData.StringEnv[constants.EnvKeyJwtPrivateKey] == "" {
|
if envData.StringEnv[constants.EnvKeyJwtPrivateKey] == "" {
|
||||||
envData.StringEnv[constants.EnvKeyJwtPrivateKey] = os.Getenv(constants.EnvKeyJwtPrivateKey)
|
envData.StringEnv[constants.EnvKeyJwtPrivateKey] = os.Getenv(constants.EnvKeyJwtPrivateKey)
|
||||||
}
|
}
|
||||||
|
18
server/sessionstore/redis_client.go
Normal file
18
server/sessionstore/redis_client.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package sessionstore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RedisSessionClient interface {
|
||||||
|
HMSet(ctx context.Context, key string, values ...interface{}) *redis.BoolCmd
|
||||||
|
Del(ctx context.Context, keys ...string) *redis.IntCmd
|
||||||
|
HDel(ctx context.Context, key string, fields ...string) *redis.IntCmd
|
||||||
|
HMGet(ctx context.Context, key string, fields ...string) *redis.SliceCmd
|
||||||
|
HGetAll(ctx context.Context, key string) *redis.StringStringMapCmd
|
||||||
|
Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *redis.StatusCmd
|
||||||
|
Get(ctx context.Context, key string) *redis.StringCmd
|
||||||
|
}
|
@@ -4,13 +4,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/go-redis/redis/v8"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type RedisStore struct {
|
type RedisStore struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
store *redis.Client
|
store RedisSessionClient
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddUserSession adds the user session to redis
|
// AddUserSession adds the user session to redis
|
||||||
|
@@ -3,6 +3,7 @@ package sessionstore
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/envstore"
|
"github.com/authorizerdev/authorizer/server/envstore"
|
||||||
@@ -121,6 +122,23 @@ func RemoveSocialLoginState(key string) {
|
|||||||
func InitSession() {
|
func InitSession() {
|
||||||
if envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL) != "" {
|
if envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL) != "" {
|
||||||
log.Println("using redis store to save sessions")
|
log.Println("using redis store to save sessions")
|
||||||
|
if isCluster(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL)) {
|
||||||
|
clusterOpt, err := getClusterOptions(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error parsing redis url:", err)
|
||||||
|
}
|
||||||
|
rdb := redis.NewClusterClient(clusterOpt)
|
||||||
|
ctx := context.Background()
|
||||||
|
_, err = rdb.Ping(ctx).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error connecting to redis cluster server", err)
|
||||||
|
}
|
||||||
|
SessionStoreObj.RedisMemoryStoreObj = &RedisStore{
|
||||||
|
ctx: ctx,
|
||||||
|
store: rdb,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
opt, err := redis.ParseURL(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL))
|
opt, err := redis.ParseURL(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Error parsing redis url:", err)
|
log.Fatalln("Error parsing redis url:", err)
|
||||||
@@ -144,3 +162,19 @@ func InitSession() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isCluster(url string) bool {
|
||||||
|
return len(strings.Split(url, ",")) > 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func getClusterOptions(url string) (*redis.ClusterOptions, error) {
|
||||||
|
hostPortsList := strings.Split(url, ",")
|
||||||
|
opt, err := redis.ParseURL(hostPortsList[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
urls := []string{opt.Addr}
|
||||||
|
urlList := hostPortsList[1:]
|
||||||
|
urls = append(urls, urlList...)
|
||||||
|
return &redis.ClusterOptions{Addrs: urls}, nil
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user