Custom callback and user profile URLs for OAuth2

For parsing `oauth2_UsernameField` values like
`profile.preferred_username`, this makes use of `eval()` which is
generally Evil™, but I'm assuming that anyone with permission to edit
config.json likely has permission to make changes to the fedwiki source
code already anyway, so it's fragile rather than increasing a security
attack surface. An alternative would be using  a small function to look
up properties of the `params` / `profile` objects using the same
dotted-path notation.
This commit is contained in:
3wc 2021-10-23 16:56:08 +02:00
parent f4f44afa35
commit 001def2fea
2 changed files with 75 additions and 11 deletions

View File

@ -1,4 +1,36 @@
## Generic OAuth 2
### Login provider set-up
Like the other PassportJS login providers, we'll need a separate "OAuth2 Client"
(others call it an "app", a "product" etc.) for our Federated Wiki instance.
How to do this varies slightly for each provider.
### `config.json`
In general, you will need to specify:
* `oauth2_clientID` -- some systems generate this for you, others allow you to
specify it
* `oauth2_clientSecret` -- secure key (keep this secret!)
* `oauth2_AuthorizationURL` and `oauth2_TokenURL` -- from your login provider's documentation
You will also need to specify a callback URL. For some providers, you can add
this when making a new "OAuth Client" for your wiki, for others you will need to
specify it with `oauth2_CallbackURL`.
You might also need to tell Federated Wiki how to look up usernames:
* `oauth2_UserInfoURL` -- from login provider's documentation
* `oauth2_UsernameField` -- starting with
* `params` for information returned in the original token request, or
* `profile` for data returned from `oauth2_UserInfoURL`, if you provided it.
Sometimes, you'll be able to look up the URLs by visiting your provider's
`/.well-known/openid-configuration` URL in a web browser.
### Examples
#### Nextcloud
```JSON
{
@ -8,8 +40,21 @@
"oauth2_clientSecret": "CLIENT SECRET",
"oauth2_AuthorizationURL": "https://auth.example.com/oauth2/authorize",
"oauth2_TokenURL": "https://auth.example.com/oauth2/token",
"wikiDomains": {
"example.wiki": {}
}
}
```
#### Keycloak
```JSON
{
"farm": true,
"security_type": "passportjs",
"oauth2_clientID": "CLIENT ID",
"oauth2_clientSecret": "CLIENT SECRET",
"oauth2_AuthorizationURL": "https://auth.example.com/auth/realms/Wiki.Cafe/protocol/openid-connect/auth",
"oauth2_TokenURL": "https://auth.example.com/auth/realms/Wiki.Cafe/protocol/openid-connect/token",
"oauth2_UserInfoURL": "https://auth.example.com/auth/realms/Wiki.Cafe/protocol/openid-connect/userinfo",
"oauth2_CallbackURL": "http://localhost:3000/auth/oauth2/callback",
"oauth2_UsernameField": "profile.preferred_username"
}
```

View File

@ -201,23 +201,42 @@ module.exports = exports = (log, loga, argv) ->
oauth2StrategyName = callbackHost + 'OAuth'
if argv.oauth2_UserInfoURL?
OAuth2Strategy::userProfile = (accesstoken, done) ->
console.log "hello"
console.log accesstoken
@_oauth2._request "GET", argv.oauth2_UserInfoURL, null, null, accesstoken, (err, data) ->
if err
return done err
try
data = JSON.parse data
catch e
return done e
done(null, data)
passport.use(oauth2StrategyName, new OAuth2Strategy({
clientID: argv.oauth2_clientID
clientSecret: argv.oauth2_clientSecret
authorizationURL: argv.oauth2_AuthorizationURL
tokenURL: argv.oauth2_TokenURL
# userURL: argv.oauth2_UserURL
# scope: 'user:emails'
# callbackURL is optional, and if it exists must match that given in
# the OAuth application settings - so we don't specify it.
tokenURL: argv.oauth2_TokenURL,
# not all providers have a way of specifying the callback URL
callbackURL: argv.oauth2_CallbackURL,
userInfoURL: argv.oauth2_UserInfoURL
}, (accessToken, refreshToken, params, profile, cb) ->
console.log("accessToken", accessToken)
console.log("refreshToken", refreshToken)
console.log("params", params)
console.log("profile", profile)
if argv.oauth2_UsernameField?
username_query = argv.oauth2_UsernameField
else
username_query = 'params.user_id'
user.oauth2 = {
id: params.user_id,
username: params.user_id,
displayName: params.user_id,
id: eval username_query,
username: eval username_query
displayName: eval username_query
}
console.log user.oauth2
cb(null, user)))
# Github Strategy