Compare commits

...

10 Commits

Author SHA1 Message Date
Lakhan Samani
5bf26f7385 fix: setting custom access token script env 2022-02-18 16:45:12 +05:30
Lakhan Samani
1b269dc6db fix: rename session_client -> redis_client 2022-02-18 09:21:02 +05:30
Lakhan Samani
ce9a115a14 Merge pull request #128 from agarwal-nitesh/feat/redis_cluster_client
Add redis cluster client as a session store.
2022-02-18 09:19:24 +05:30
Nitesh Agarwal
f2f4c72aa6 Add redis cluster client as a session store. 2022-02-17 20:49:54 +05:30
Samyak Bhuta
9970eb16c9 Update README
Minor changes.
2022-02-17 15:04:05 +05:30
Lakhan Samani
23e53286bd Merge pull request #124 from anik-ghosh-au7/feat/jwt-types
support for more jwt encryption types added
2022-02-14 18:56:06 +05:30
Anik Ghosh
47acff05e2 support for more jwt encryption types added 2022-02-14 16:00:35 +05:30
Lakhan Samani
5572928619 fix: remove redundunt break statement 2022-02-12 22:55:33 +05:30
Lakhan Samani
85b4cd6339 Add support for maria db 2022-02-12 22:49:53 +05:30
Lakhan Samani
f0d38ab260 Merge pull request #121 from authorizerdev/feat/add-jwt-algos
feat: add jwt algos
2022-02-12 19:37:28 +05:30
12 changed files with 160 additions and 54 deletions

3
.gitignore vendored
View File

@@ -10,4 +10,5 @@ build
data.db data.db
.DS_Store .DS_Store
.env.local .env.local
*.tar.gz *.tar.gz
.vscode/

View File

@@ -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

View File

@@ -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,
})
}
/> />
); );
} }

View File

@@ -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',
};

View File

@@ -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,

View File

@@ -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>

View File

@@ -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"
) )

View File

@@ -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
View File

@@ -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)
} }

View 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
}

View File

@@ -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

View File

@@ -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
}