Skip to content

Commit 884a2b2

Browse files
committed
add HTTP Bearer auth documentation
1 parent 3ac39d7 commit 884a2b2

File tree

3 files changed

+153
-18
lines changed

3 files changed

+153
-18
lines changed

configuration/index.md

+75-10
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,21 @@ Fano Framework provides `IAppConfiguration` interface for that purpose.
1414

1515
## IAppConfiguration
1616

17-
`IAppConfiguration` interface provides two methods
17+
`IAppConfiguration` interface provides several methods,
1818

19-
- `getString()` which accepts name and returns string value
20-
- `getInt()` which accept name returns integer value
21-
- `getBool()` which accept name returns boolean value
19+
- `getString()` accepts name and returns string value.
20+
- `getInt()` accepts name returns integer value.
21+
- `getBool()` accepts name returns boolean value.
22+
- `getFloat()` accepts name returns double value.
23+
- `has()` test if name is exists in configuration.
2224

2325
## Built-in IAppConfiguration implementation
2426

25-
Fano Framework provides `TJsonFileConfig` and `TIniFileConfig` class which loads configuration data from JSON and INI file respectively. Also available `TNullConfig` which is null class implements `IAppConfiguration` interface.
27+
Fano Framework provides `TJsonFileConfig`, `TIniFileConfig`, `TEnvConfig` class which loads configuration data from JSON, INI file and environment variables respectively.
2628

27-
Load config from JSON,
29+
Fano Framework also provides `TCompositeConfig` and `TNullConfig` class. First one is `IAppConfiguration` implementation with capability to combine two`IAppConfiguration` instance and latter is null class implements `IAppConfiguration` interface.
30+
31+
### Load config from JSON
2832

2933
```
3034
var config : IAppConfiguration;
@@ -34,7 +38,7 @@ config := TJsonFileConfig.create(
3438
);
3539
```
3640

37-
Load config from INI,
41+
### Load config from INI
3842

3943
```
4044
var config : IAppConfiguration;
@@ -46,9 +50,36 @@ config := TIniFileConfig.create(
4650
```
4751
Last parameter is name of default section to use. Read [INI file configuration](#ini-file-configuration) section in this document for more information.
4852

49-
To be able to use `TJsonFileConfig` and `TIniFileConfig` class with [dependency container](/dependency-container), Fano Framework provides `TJsonFileConfigFactory` and `TIniFileConfigFactory` class which enables you to register above classes in container.
53+
### Load configuration from environment variables
54+
55+
```
56+
var config : IAppConfiguration;
57+
...
58+
config := TEnvConfig.create();
59+
```
60+
61+
### Combine multiple configurations as one
62+
63+
`TCompositeConfig` allows you to use multiple configurations. In following setup,
64+
if configuration not found in environment variables, then it will try to find it in
65+
config.json.
66+
67+
```
68+
var config : IAppConfiguration;
69+
...
70+
config := TCompositeConfig.create(
71+
TEnvConfig.create(),
72+
TJsonFileConfig.create(
73+
getCurrentDir() + '/config/config.json'
74+
)
75+
);
76+
```
77+
78+
## Register config instance to dependency container
79+
80+
To be able to use `TJsonFileConfig`, `TIniFileConfig`, `TEnvConfig`, `TCompositeConfig` and `TNullConfig` class with [dependency container](/dependency-container), Fano Framework provides `TJsonFileConfigFactory`, `TIniFileConfigFactory`, `TEnvConfigFactory`, `TCompositeConfigFactory` and `TNullConfigFactory` class which enables you to register above classes in container.
5081

51-
Register JSON config
82+
### Register JSON config
5283
```
5384
container.add(
5485
'config',
@@ -58,7 +89,7 @@ container.add(
5889
);
5990
```
6091

61-
Register INI config
92+
### Register INI config
6293
```
6394
container.add(
6495
'config',
@@ -68,6 +99,26 @@ container.add(
6899
);
69100
```
70101

102+
### Register environment variable config
103+
```
104+
container.add(
105+
'config',
106+
TEnvConfigFactory.create()
107+
);
108+
```
109+
110+
### Register composite configurations
111+
```
112+
container.add(
113+
'config',
114+
TCompositeConfigFactory.create(
115+
TNullConfigFactory.create(),
116+
TJsonFileConfigFactory.create(getCurrentDir() + '/config/config.json')
117+
)
118+
);
119+
```
120+
121+
### Retrieve configuration instance from dependency container
71122

72123
To get configuration instance
73124

@@ -76,6 +127,11 @@ var config : IAppConfiguration;
76127
...
77128
config := container.get('config') as IAppConfiguration;
78129
```
130+
or with array-like syntax
131+
132+
```
133+
config := container['config'] as IAppConfiguration;
134+
```
79135

80136
## Read configuration data
81137

@@ -123,6 +179,15 @@ var cookieMaxAge : integer;
123179
cookieMaxAge := config.getInt('cookie.maxAge');
124180
```
125181

182+
`getString()`, `getInt()`, `getBool()` and `getFloat()` methods accept second parameter
183+
if you want to use different value when key does not exist.
184+
185+
```
186+
baseUrl := config.getString('baseUrl', 'https://example.com');
187+
```
188+
If key `baseUrl` is not found, it returns second parameter value.
189+
190+
126191
## <a name="ini-file-configuration"></a>INI file configuration
127192

128193
`TIniFileConfig` is thin wrapper of Free Pascal `TIniFile`. `TIniFile` cannot read data from INI file that has no section. Your INI file must contain at least one section which serve as default section. The last parameter of `TIniFileConfig`'s constructor expect name of default section. If you use `TIniFileConfigFactory`, by default it uses `fano` as default section if not specified. You can specify default section by calling `setDefaultSection()` method as shown in following code.

security/http-authentication/index.md

+50-1
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,62 @@ router.get('/', container['homeController'] as IRequestHandler)
158158
.add(container['digestAuthMiddleware'] as IMiddleware);
159159
```
160160

161+
## Handling Bearer Authentication with middleware
162+
163+
Fano Framework provides implementation for bearer type HTTP authentication with
164+
`TBearerAuthMiddleware` middleware with purpose to simplify task to protect access of certain routes using Bearer HTTP authentication scheme.
165+
166+
Constructor of `TBearerAuthMiddleware` expects three parameters,
167+
168+
- Instance of `ITokenVerifier` interface which is responsible to perform actual token verification.
169+
- String of realm name.
170+
- String of credential key name where authenticated credential can be queried from request.
171+
172+
Currently, Fano Framework supports JSON Web Token (JWT) verification only via `TJwtTokenVerifier`
173+
class which implements `ITokenVerifier` interface.
174+
175+
After token is verified, credential info found in token is stored in request which later can be queried
176+
in controller using name you defined in credential key name.
177+
178+
## Register Bearer Authentication middleware with container
179+
180+
Fano Framework has `TBearerAuthMiddlewareFactory` class
181+
which allows you to register `TBearerAuthMiddleware` into service container.
182+
183+
```
184+
container.add(
185+
'bearerAuth',
186+
TBearerAuthMiddlewareFactory.create()
187+
.realm('fano-realm')
188+
.verifier(container['tokenVerifier'] as ITokenVerifier)
189+
);
190+
```
191+
192+
## Attach Bearer Auth middleware to application routes
193+
194+
Attach bearer auth middleware instance to application routes, for example
195+
196+
```
197+
router.get('/', container['homeController'] as IRequestHandler)
198+
.add(container['bearerAuth'] as IMiddleware);
199+
```
200+
For every GET request to URL `/`, middleware will check token existence and verify
201+
if it is found. If token is not found or not verified, it returns HTTP 401 response
202+
with `WWW-Authenticate: Bearer realm="[realm name]"` header,
203+
where `[realm name]` is realm that you set above.
204+
161205
## Security consideration
162206

163207
For Basic HTTP authentication scheme, username and password is transmitted as Base64-encoded string. It is prone to man in middle attack and it is must be used in conjunction with SSL/TLS.
164208

165209
Digest HTTP authentication scheme is more computation expensive but can be used with or without SSL/TLS because password and other data is sent to server as MD5 hashed value. However, because MD5 hash is not cryptographically strong, you need to be cautious when use it without SSL/TLS.
166210

167-
If your application is running behind reverse proxy, for example, with `mod_proxy_scgi` module, Apache does not pass `Authorization` header to application because of security concern.
211+
For Bearer HTTP authentication, token is credential. It must be used in conjunction with SSL/TLS
212+
to avoid man in middle attack. Token may or may not be encrypted. If you use
213+
unencrypted JWT token, do not store sensitive data in token.
214+
215+
### Missing Authorization header
216+
If your application is running behind reverse proxy, for example, with `mod_proxy_scgi` module, Apache does not pass `Authorization` header to application because of security concern. This will cause all middlewares above return HTTP 401 as they can not find this header.
168217

169218
In case, you have trusted network between Apache and your application, simple solution is to transform `Authorization` header into `HTTP_AUTHORIZATION` environment variable using `mod_rewrite` module.
170219

security/password-hash/index.md

+28-7
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ description: Password hash in Fano Framework
1111

1212
## Password hash and verification
1313

14-
Fano Framework provides several password hash algorithm based on [HashLib4Pascal library](https://github.com/Xor-el/HashLib4Pascal).
14+
Fano Framework provides several password hash algorithm based on [HashLib4Pascal](https://github.com/Xor-el/HashLib4Pascal) and [BCrypt](https://github.com/viniciussanchez/bcrypt) libraries.
1515

16-
Fano Framework provides simple wrapper for this library through `IPasswordHash` interface.
16+
Fano Framework provides simple wrapper for these libraries through `IPasswordHash` interface.
1717

1818
### Generate password hash
1919

@@ -53,8 +53,7 @@ passwHash.salt('some random value');
5353

5454
#### Cost
5555
To make generating password expensive, some password hash algorithm requires you to set number of iterations as cost of algorithm.
56-
Higher value usually means higher computation resources. You should think carefully about this value as this is trade-off between
57-
security and performance.
56+
Higher value usually means higher computation resources. You should think carefully about this value as this is trade-off between security and performance.
5857

5958
To set cost, call `cost()` method with integer value for cost.
6059
This method returns current password hash instance.
@@ -64,15 +63,15 @@ passwHash.cost(1024);
6463
```
6564

6665
#### Memory cost
67-
Some algorithm employ memory cost.
66+
Some algorithm employs memory cost, such as Argon2i. For other, this value is ignored.
6867

6968
To set memory cost, you call `memory()` method of `IPasswordHash` interface. This method returns current password hash instance.
7069

7170
```
7271
passwHash.memory(32);
7372
```
7473
#### Paralleism
75-
Some algorithm employ paralleism cost.
74+
Some algorithm employs paralleism cost.
7675

7776
To set paralleism cost, you call `paralleism()` method of `IPasswordHash` interface. This method returns current password hash instance.
7877

@@ -97,7 +96,7 @@ passwHash.len(64);
9796

9897
## Available password hash implementations
9998

100-
Currently, Fano Framework provides `IPasswordHash` implementation for [Argon2i](https://en.wikipedia.org/wiki/Argon2), [PBKDF2](https://tools.ietf.org/html/rfc2898), [Scrypt](https://tools.ietf.org/html/rfc7914) and SHA2.
99+
Currently, Fano Framework provides `IPasswordHash` implementation for [Argon2i](https://en.wikipedia.org/wiki/Argon2), [PBKDF2](https://tools.ietf.org/html/rfc2898), [Scrypt](https://tools.ietf.org/html/rfc7914), [BCrypt](https://en.wikipedia.org/wiki/Bcrypt) and SHA2.
101100

102101
### PBKDF2 password hash
103102

@@ -124,6 +123,19 @@ container.add('passwHash', TArgon2iPasswordHashFactory.create());
124123
```
125124
See PBKDF2 code above to retrieve password hash instance.
126125

126+
You can set initial setting values for password hash instance, for example
127+
128+
```
129+
container.add(
130+
'passwHash',
131+
TArgon2iPasswordHashFactory.create()
132+
.cost(4)
133+
.memory(32)
134+
.paralleism(4)
135+
.len(32)
136+
);
137+
```
138+
127139
### Scrypt password hash
128140

129141
To use Scrypt password hash, you need to use `TScryptPasswordHash` class. You can register this class with dependency container using its factory class `TScryptPasswordHashFactory`.
@@ -133,6 +145,15 @@ To register password hash,
133145
container.add('passwHash', TScryptPasswordHashFactory.create());
134146
```
135147

148+
### BCrypt password hash
149+
150+
To use BCrypt password hash, you need to use `TBcryptPasswordHash` class. You can register this class with dependency container using its factory class `TBcryptPasswordHashFactory`.
151+
152+
To register password hash,
153+
```
154+
container.add('passwHash', TBcryptPasswordHashFactory.create());
155+
```
156+
136157
### SHA2 password hash
137158

138159
While you are advised not to use SHA2 for password hash, Fano Framework provides `IPasswordHash` implementation for SHA1 256 bit and 512 bit using `TSHA2_256PasswordHash` and `TSHA2_512PasswordHash` class.

0 commit comments

Comments
 (0)