Skip to content

Commit

Permalink
Merge 75c6ad0 into 34b4b66
Browse files Browse the repository at this point in the history
  • Loading branch information
Badgerati committed Feb 16, 2020
2 parents 34b4b66 + 75c6ad0 commit 616949a
Show file tree
Hide file tree
Showing 9 changed files with 455 additions and 34 deletions.
17 changes: 10 additions & 7 deletions docs/Tutorials/Authentication/Methods/Basic.md
Expand Up @@ -4,7 +4,7 @@ Basic Authentication is when you pass an encoded `username:password` value on th

## Setup

To setup and start using Form Authentication in Pode you use the `New-PodeAuthType -Basic` function, and then pipe this into the [`Add-PodeAuth`](../../../../Functions/Authentication/Add-PodeAuth) function:
To setup and start using Basic Authentication in Pode you use the `New-PodeAuthType -Basic` function, and then pipe this into the [`Add-PodeAuth`](../../../../Functions/Authentication/Add-PodeAuth) function. The [`Add-PodeAuth`](../../../../Functions/Authentication/Add-PodeAuth) function's ScriptBlock is supplied the username and password:

```powershell
Start-PodeServer {
Expand All @@ -28,7 +28,7 @@ Start-PodeServer {
}
```

## Validating
## Middleware

Once configured you can start using Basic Authentication to validate incoming Requests. You can either configure the validation to happen on every Route as global Middleware, or as custom Route Middleware.

Expand Down Expand Up @@ -64,13 +64,16 @@ Start-PodeServer {
# here you'd check a real user storage, this is just for example
if ($username -eq 'morty' -and $password -eq 'pickle') {
return @{ 'user' = @{
'ID' ='M0R7Y302'
'Name' = 'Morty';
'Type' = 'Human';
} }
return @{
User = @{
'ID' ='M0R7Y302'
'Name' = 'Morty';
'Type' = 'Human';
}
}
}
# authentication failed
return $null
}
Expand Down
84 changes: 73 additions & 11 deletions docs/Tutorials/Authentication/Methods/Custom.md
@@ -1,47 +1,108 @@
# Custom

Custom authentication works much like the inbuilt types (Basic and Form), but allows you to specify your own parsing logic, as well as any custom options that might be required.
Custom authentication works much like the inbuilt types (Basic/Form/etc), but allows you to specify your own parsing logic, as well as any custom options that might be required.

## Setup and Parsing

To setup and start using Custom authentication in Pode you use the `New-PodeAuthType -Custom` function, and then pipe this into the [`Add-PodeAuth`](../../../../Functions/Authentication/Add-PodeAuth) function.
To setup and start using Custom authentication in Pode you use the `New-PodeAuthType -Custom` function, and then pipe this into the [`Add-PodeAuth`](../../../../Functions/Authentication/Add-PodeAuth) function.

Let's say we wanted something similar to [`Form`](../Form) Authentication, but it requires a third piece of information: `ClientName`. To setup Custom Authentication for this method, you'll need to specify the parsing logic within the `-ScriptBlock`.
Let's say we wanted something similar to [`Form`](../Form) Authentication, but it requires a third piece of information: `ClientName`. To setup Custom Authentication for this method, you'll need to specify the parsing logic within the `-ScriptBlock` of the [`New-PodeAuthType`](../../../../Functions/Authentication/New-PodeAuthType) function.

The `-ScriptBlock` on [`New-PodeAuthType`](../../../../Functions/Authentication/New-PodeAuthType) will be passed the current web event (containing the `Request`/`Response` objects, much like a Route). In this script you can parse the Request payload/headers for any credential information that needs validating. Once sourced, the data returned from the script should be either an `array`, which will then splatted onto the `-ScriptBlock` from your [`New-PodeAuthType`](../../../../Functions/Authentication/New-PodeAuthType) function:
The `-ScriptBlock` on [`New-PodeAuthType`](../../../../Functions/Authentication/New-PodeAuthType) will be passed the current web event (containing the `Request`/`Response` objects, and other pieces of information much like on Routes or Middleware). In this script you can parse the Request payload/headers for any credential information that needs validating. Once sourced the data returned from the script should be an `array`, which will then splatted onto the `-ScriptBlock` from your [`Add-PodeAuth`](../../../../Functions/Authentication/Add-PodeAuth) function:

```powershell
Start-PodeServer {
# define a new custom authentication type
$custom_type = New-PodeAuthType -Custom -ScriptBlock {
param($e, $opts)
# get client/user/pass field names to get from payload
# get client/user/password field names
$clientField = (Protect-PodeValue -Value $opts.ClientField -Default 'client')
$userField = (Protect-PodeValue -Value $opts.UsernameField -Default 'username')
$passField = (Protect-PodeValue -Value $opts.PasswordField -Default 'password')
# get the client/user/pass from the post data
# get the client/user/password from the request's post data
$client = $e.Data.$clientField
$username = $e.Data.$userField
$password = $e.Data.$passField
# return the data, to be passed to the validator script
# return the data in a array, which will be passed to the validator script
return @($client, $username, $password)
}
# now, add a new custom authentication method
# now, add a new custom authentication method using the type you created above
$custom_type | Add-PodeAuth -Name 'Login' -ScriptBlock {
param($client, $username, $password)
# check if the client is valid
# check if the client is valid in some database
# return a user object (return $null if validation failed)
return @{ User = $user }
}
}
```

!!! note
The `$opts` parameter in the `New-PodeAuthType` ScriptBlock come from the `-ArgumentList` HashTable.

## Post Validation

The typical setup of authentication is that you create some type to parse the request ([`New-PodeAuthType`](../../../../Functions/Authentication/New-PodeAuthType)), and then you pipe this into a validator/method to validate the parsed user's credentials ([`Add-PodeAuth`](../../../../Functions/Authentication/Add-PodeAuth)).

There is however also an optional `-PostValidator` ScriptBlock that can be passed to your Custom Authentication type on the [`New-PodeAuthType`](../../../../Functions/Authentication/New-PodeAuthType) function. This `-PostValidator` script runs after normal user validation, as is supplied the current web event, the original splatted array returned from the [`New-PodeAuthType`](../../../../Functions/Authentication/New-PodeAuthType) ScriptBlock, and also the result HashTable from the validator. You can use this script to re-generate any hashes for further validation, but if successful you *must* return the User object again (ie: re-return the last parameter which is the original validation result).

For example, if you have a post validator script for the above Client Custom Authentication, then it would be supplied the following parameters:

* Web Event
* ClientName
* Username
* Password
* ClientName
* Validation Result

For example:

```powershell
Start-PodeServer {
# define a new custom authentication type
$custom_type = New-PodeAuthType -Custom -ScriptBlock {
param($e, $opts)
# get client/user/password field names
$clientField = (Protect-PodeValue -Value $opts.ClientField -Default 'client')
$userField = (Protect-PodeValue -Value $opts.UsernameField -Default 'username')
$passField = (Protect-PodeValue -Value $opts.PasswordField -Default 'password')
# get the client/user/password from the request's post data
$client = $e.Data.$clientField
$username = $e.Data.$userField
$password = $e.Data.$passField
# return the data in a array, which will be passed to the validator script
return @($client, $username, $password)
} `
-PostValidator {
param($e, $client, $username, $password, $result)
# run any extra post-validation logic
# the result is the object returned from the below scriptblock
return $result
}
# now, add a new custom authentication method using the type you created above
$custom_type | Add-PodeAuth -Name 'Login' -ScriptBlock {
param($client, $username, $password)
# check if the client is valid in some database
# return a user object (return $null if validation failed)
return @{ User = $user }
}
}
```

## Validating
## Middleware

Once configured you can start using the Custom Authentication to validate incoming Requests. You can either configure the validation to happen on every Route as global Middleware, or as custom Route Middleware.

Expand All @@ -53,7 +114,7 @@ Start-PodeServer {
}
```

Whereas the following example will use Custom authentication to only validate requests on specific a `route`:
Whereas the following example will use Custom authentication to only validate requests on specific a Route:

```powershell
Start-PodeServer {
Expand Down Expand Up @@ -95,6 +156,7 @@ Start-PodeServer {
# check if the client is valid
# return a user object (return $null if validation failed)
return @{ User = $user }
}
Expand Down
98 changes: 98 additions & 0 deletions docs/Tutorials/Authentication/Methods/Digest.md
@@ -0,0 +1,98 @@
# Digest

Digest Authentication lets you authenticate a user without actually sending the password to the server. Instead the a request is made to the server, and a challenge issued back for credentials. The authentication is then done by comparing hashes generated by the client and server using the user's password as a secret key.

## Setup

To setup and start using Digest Authentication in Pode you use the `New-PodeAuthType -Digest` function, and then pipe this into the [`Add-PodeAuth`](../../../../Functions/Authentication/Add-PodeAuth) function. The parameters supplied to the [`Add-PodeAuth`](../../../../Functions/Authentication/Add-PodeAuth) function's ScriptBlock are the `$username`, and a HashTable containing the parameters from the Authorization header:

```powershell
Start-PodeServer {
New-PodeAuthType -Digest | Add-PodeAuth -Name 'Authenticate' -ScriptBlock {
param($username, $params)
# check if the user is valid
return @{ User = $user; Password = $password }
}
}
```

Unlike other forms of authentication where you only need return the User on success. Digest requires you to also return the Password of the user as a separate property. This password is what is used as the secret key to generate the client's response hash, and allows the server to re-generate the hash for validation. (Not returning the password will result in an HTTP 401 challenge response).

By default, Pode will check if the Request's header contains an `Authorization` key, and whether the value of that key starts with `Digest`. Pode will also gather the rest of the parameters in the header such as the Nonce, NonceCount, etc. An HTTP 401 challenge will be sent back if the Authorization header is invalid.

The HashTable of parameters sent to the [`Add-PodeAuth`](../../../../Functions/Authentication/Add-PodeAuth) functions's ScriptBlock are the following:

| Parameter | Description |
| --------- | ----------- |
| cnonce | A nonce value generated by the client |
| nc | The count of time the client has used the server nonce |
| nonce | A nonce value generated by the server |
| qop | Fixed to 'auth' |
| realm | The realm description from the server's HTTP 401 challenge |
| response | The generated hash value of all these parameters from the client |
| uri | The URI path that needs authentication |
| username | The username of the user that needs authenticating |

## Middleware

Once configured you can start using Digest Authentication to validate incoming Requests. You can either configure the validation to happen on every Route as global Middleware, or as custom Route Middleware.

The following will use Digest Authentication to validate every request on every Route:

```powershell
Start-PodeServer {
Get-PodeAuthMiddleware -Name 'Authenticate' | Add-PodeMiddleware -Name 'GlobalAuthValidation'
}
```

Whereas the following example will use Digest authentication to only validate requests on specific a Route:

```powershell
Start-PodeServer {
Add-PodeRoute -Method Get -Path '/info' -Middleware (Get-PodeAuthMiddleware -Name 'Authenticate') -ScriptBlock {
# logic
}
}
```

## Full Example

The following full example of Digest authentication will setup and configure authentication, validate that a user's username is valid, and then validate on a specific Route:

```powershell
Start-PodeServer {
Add-PodeEndpoint -Address * -Port 8080 -Protocol Http
# setup digest authentication to validate a user
New-PodeAuthType -Digest | Add-PodeAuth -Name 'Authenticate' -ScriptBlock {
param($username, $params)
# here you'd check a real user storage, this is just for example
if ($username -eq 'morty') {
return @{
User = @{
'ID' ='M0R7Y302'
'Name' = 'Morty';
'Type' = 'Human';
}
Password = 'pickle'
}
}
# authentication failed
return $null
}
# check the request on this route against the authentication
Add-PodeRoute -Method Get -Path '/cpu' -Middleware (Get-PodeAuthMiddleware -Name 'Authenticate') -ScriptBlock {
Write-PodeJsonResponse -Value @{ 'cpu' = 82 }
}
# this route will not be validated against the authentication
Add-PodeRoute -Method Get -Path '/memory' -ScriptBlock {
Write-PodeJsonResponse -Value @{ 'memory' = 14 }
}
}
```
2 changes: 1 addition & 1 deletion docs/Tutorials/Authentication/Methods/Form.md
Expand Up @@ -28,7 +28,7 @@ Start-PodeServer {
}
```

## Validating
## Middleware

Once configured you can start using Form Authentication to validate incoming Requests. You can either configure the validation to happen on every Route as global Middleware, or as custom Route Middleware.

Expand Down
29 changes: 21 additions & 8 deletions docs/Tutorials/Authentication/Overview.md
Expand Up @@ -7,17 +7,18 @@ Authentication can either be sessionless (requiring validation on every request)

To setup and use authentication in Pode you need to use the [`New-PodeAuthType`](../../../Functions/Authentication/New-PodeAuthType) and [`Add-PodeAuth`](../../../Functions/Authentication/Add-PodeAuth) functions, as well as the [`Get-PodeAuthMiddleware`](../../../Functions/Authentication/Get-PodeAuthMiddleware) function for defining authentication Middleware.

## Functions
## Usage

### New-PodeAuthType
### Types/Parsers

The [`New-PodeAuthType`](../../../Functions/Authentication/New-PodeAuthType) function allows you to create and configure Basic/Form authentication types, or you can create your own Custom authentication types. These types can then be used on the [`Add-PodeAuth`](../../../Functions/Authentication/Add-PodeAuth) function.
The [`New-PodeAuthType`](../../../Functions/Authentication/New-PodeAuthType) function allows you to create and configure Basic/Digest/Form authentication types/parsers, or you can create your own Custom authentication types. These types can then be used on the [`Add-PodeAuth`](../../../Functions/Authentication/Add-PodeAuth) function. There job is to parse the request for any user credentials, or other information, that is required for a user to be authenticated.

An example of creating Basic/Form authentication is as follows:
An example of creating Basic/Digest/Form authentication is as follows:

```powershell
Start-PodeServer {
$basic_auth = New-PodeAuthType -Basic
$digest_auth = New-PodeAuthType -Digest
$form_auth = New-PodeAuthType -Form
}
```
Expand All @@ -39,15 +40,15 @@ Start-PodeServer {
$username = $e.Data.$userField
$password = $e.Data.$passField
# return the data, to be passed to the validator script
# return the data as an array, to be passed to the validator script
return @($client, $username, $password)
}
}
```

### Add-PodeAuth
### Method/Validator

The [`Add-PodeAuth`](../../../Functions/Authentication/Add-PodeAuth) function allows you to add authentication methods to your server. You can have many methods configured, defining which one to validate against using the [`Get-PodeAuthMiddleware`](../../../Functions/Authentication/Get-PodeAuthMiddleware) function.
The [`Add-PodeAuth`](../../../Functions/Authentication/Add-PodeAuth) function allows you to add authentication methods/validators to your server. You can have many methods configured, defining which one to validate against using the [`Get-PodeAuthMiddleware`](../../../Functions/Authentication/Get-PodeAuthMiddleware) function. There job is the validate the information parsed from the supplied type to ensure a user is valid.

An example of using [`Add-PodeAuth`](../../../Functions/Authentication/Add-PodeAuth) for Basic authentication is as follows:

Expand Down Expand Up @@ -97,6 +98,18 @@ New-PodeAuthType -Basic | Add-PodeAuth -Name 'Login' -ScriptBlock {
}
```

If you're defining an authenticator that need to send back a Challenge, then you can also do this by setting the response Code property to 401, and also supplying a Challenge property.
This Challenge property is a string, and will be automatically appended onto the `WWW-Authenticate` Header. It *does not* need to include the Authentication Type or Realm (these will be added for you).

For example, in Digest you could return:

```powershell
return @{
Code = 401
Challenge = 'qop="auth", nonce="<some-random-guid>"'
}
```

#### Authenticate Type/Realm

When authentication fails, and a 401 response is returned, then Pode will also attempt to Response back to the client with a `WWW-Authenticate` header (if you've manually set this header using the custom headers from above, then the custom header will be used instead). For the inbuilt types, such as Basic, this Header will always be returned on a 401 response.
Expand All @@ -118,7 +131,7 @@ WWW-Authenticate: Basic realm="Enter creds to access site"
!!! note
If no Realm was set then it would just look as follows: `WWW-Authenticate: Basic`

### Get-PodeAuthMiddleware
### Middleware

The [`Get-PodeAuthMiddleware`](../../../Functions/Authentication/Get-PodeAuthMiddleware) function allows you to define which authentication method to validate a Request against. It returns valid Middleware, meaning you can either use it on specific Routes, or globally for all routes as global Middleware. If this action fails, then a 401 response is returned.

Expand Down

0 comments on commit 616949a

Please sign in to comment.