Skip to content

Commit

Permalink
Moved to base64 and json encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
Philip Reichenberger committed Jun 8, 2018
1 parent 1b3f9ca commit 2a2af43
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 26 deletions.
21 changes: 12 additions & 9 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,30 @@ Grab a release from: https://github.com/preichenberger/oauth2-router/releases
### Docker
https://hub.docker.com/r/preichenberger/oauth2-router


## Start
```bash
$ oauth2-router -port 3000
$ 2018/06/08 12:48:09 Starting OAuth2 Router on port: 3000
```

## Example
Using the following information:
Coding examples

For the following info:
- OAuth2 Router redirect_uri: http://localhost:8080
- Real redirect_uri: http://localhost:5000/random_endpoint?apple=pears
- Authorization code from callback: secretcode
- Original state parameter(URL encoded): csrf%3D1234
- OAuth2 Router state parameter(URL encoded): csrf%3D1234%26redirect%3Dhttp%3A%2F%2Flocalhost%3A5000%2Frandom_endpoint%3Fapple%3Dpears

Setting the state parameter must be implemented by the user's code. It must include a query parameter 'redirect' which is the real redirect_uri that you will be redirecting to.

```bash
curl "http://localhost:8080?code=secretcode&state=csrf%3D1234%26redirect%3Dhttp%3A%2F%2Flocalhost%3A5000%2Frandom_endpoint%3Fapple%3Dpears"
<a href="http://localhost:5000/random_endpoint?apple=pears&amp;code=secretcode&amp;state=csrf%3D1234%26redirect%3Dhttp%3A%2F%2Flocalhost%3A5000%2Frandom_endpoint%3Fapple%3Dpears">Moved Permanently</a>.
1. Add the OAuth2 Router redirect_uri: http://localhost:8080 to your OAuth2 provider (Google, Facebook, Github, etc...)
2. Create a JSON with any date to be passed in the OAuth2 state parameter. Add a redirect parameter, with the real redirect_uri
```json
{
"csrf": "39adsijdfiaj",
"redirect": http://localhost:5000/random_endpoint?apple=pears
}
```
3. Base64 encode the json and set it as the state parameter in the OAuth2 implementation
4. Use OAuth2

## Tests
Run tests
Expand Down
19 changes: 16 additions & 3 deletions redirector/url.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
package redirector

import (
"encoding/base64"
"encoding/json"
"net/url"
)

func CreateUrl(queryValues url.Values) (*url.URL, error) {
var stateValues map[string]string

if _, ok := queryValues["state"]; !ok {
return nil, ValidationError{"Missing state field"}
}

stateValues, err := url.ParseQuery(queryValues["state"][0])
stateQuery, err := base64.StdEncoding.DecodeString(queryValues["state"][0])
if err != nil {
return nil, ValidationError{"State field is not a query string"}
return nil, ValidationError{"Could not base64 decode state value"}
}

if err := json.Unmarshal(stateQuery, &stateValues); err != nil {
return nil, ValidationError{"Could not json decode state value"}
}

if _, ok := stateValues["redirect"]; !ok {
return nil, ValidationError{"Query param redirect missing from state"}
}

redirectUrl, err := url.ParseRequestURI(stateValues["redirect"][0])
redirect, err := url.QueryUnescape(stateValues["redirect"])
if err != nil {
return nil, ValidationError{"Could not URL decode redirect value"}
}

redirectUrl, err := url.ParseRequestURI(redirect)
if err != nil {
return nil, ValidationError{"Could not parse redirect URL"}
}
Expand Down
58 changes: 44 additions & 14 deletions redirector/url_test.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,49 @@
package redirector

import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/url"
"testing"
)

func TestCreateUrl(t *testing.T) {
csrfString := "test313"
redirectUrlString := "https://www.github.com/test?callback=3&callback=4"
func createStateValue(values map[string]string) (string, error) {
data, err := json.Marshal(values)
if err != nil {
return "", err
}

return base64.StdEncoding.EncodeToString(data), nil
}

func TestCreateUrl(t *testing.T) {
queryValues := url.Values{}
queryValues.Add("code", "3")
queryValues.Add("code", "5")

stateQueryValues := url.Values{}
stateQueryValues.Add("csrf", csrfString)
stateQueryValues.Add("redirect", redirectUrlString)
println(stateQueryValues.Encode())
queryValues.Add("state", stateQueryValues.Encode())
stateValues := map[string]string{
"csrf": "test123",
"redirect": "https://www.github.com/test?callback=3&callback=4",
}

state, err := createStateValue(stateValues)
if err != nil {
t.Error(err)
}
queryValues.Add("state", state)

redirectUrl, err := CreateUrl(queryValues)
if err != nil {
t.Error(err)
}

expected := fmt.Sprintf("https://www.github.com/test?callback=3&callback=4&code=3&code=5&state=%s",
url.QueryEscape(stateQueryValues.Encode()))
url.QueryEscape(state))

if redirectUrl.String() != expected {
errMsg := fmt.Sprintf("CreateUrl does not match expected response:\nResult:%s\nExpected: %s", redirectUrl.String(), expected)
errMsg := fmt.Sprintf("CreateUrl does not match expected response:\n Result: %s\nExpected: %s", redirectUrl.String(), expected)
t.Error(errors.New(errMsg))
}
}
Expand All @@ -42,20 +56,36 @@ func TestCreateUrlMissingStateError(t *testing.T) {
}

func TestCreateUrlMissingRedirectError(t *testing.T) {
stateValues := map[string]string{
"test": "test",
}

queryValues := url.Values{}
queryValues.Add("state", "test=3")
state, err := createStateValue(stateValues)
if err != nil {
t.Error(err)
}
queryValues.Add("state", state)

_, err := CreateUrl(queryValues)
_, err = CreateUrl(queryValues)
if err.Error() != "Query param redirect missing from state" {
t.Error(errors.New("Missing query param redirect error"))
}
}

func TestCreateUrlRedirectParseError(t *testing.T) {
stateValues := map[string]string{
"redirect": "http;test",
}

queryValues := url.Values{}
queryValues.Add("state", "redirect=http/test")
state, err := createStateValue(stateValues)
if err != nil {
t.Error(err)
}
queryValues.Add("state", state)

_, err := CreateUrl(queryValues)
_, err = CreateUrl(queryValues)
if err.Error() != "Could not parse redirect URL" {
t.Error(errors.New("Missing could not parse redirect error"))
}
Expand Down

0 comments on commit 2a2af43

Please sign in to comment.