Skip to content

Commit

Permalink
Update scopes used in OAuth (andregasser#382)
Browse files Browse the repository at this point in the history
* Update scopes used in OAuth

- makes all scope parameters in OAuth and App methods optional. Endpoints not receiving a scope parameter will default to granting "read" permission.
- removes default parameter value from Scope constructor. Users will need to define a certain scope if they want to use it.
Closes andregasser#116.

- adds all scopes as defined by Mastodon, marks existing scopes FOLLOW and ALL as deprecated.
- removes all internal usage of the now deprecated ALL scope.
Closes andregasser#143.

- moves deduplication of scopes from a separate function into the one building the parameter string. This avoids unnecessarily throwing an IllegalArgumentException.
Closes andregasser#381.

* Enhance Scope usage in tests

- in integration tests, declare "full scope" once
- in unit tests, do not specify any Scope unless directly tested
- remove deprecated "follow" scope from the access token asset

* In samples to get access token, ensure that scopes requested for the token match those in OAuth URL.

* Enable hierarchical access to defined scopes

- replace Name enum with hierarchical structure for a more intuitive access to individual scopes
- changing samples and USAGE.md to match

Examples:
- Scope(Scope.Name.READ) becomes Scope(Scope.READ.ALL)
- Scope(Scope.Name.ADMIN_READ_ACCOUNTS) becomes Scope(Scope.ADMIN.READ.ACCOUNTS)

---------

Co-authored-by: Patrick Geselbracht <[email protected]>
  • Loading branch information
bocops and PattaFeuFeu authored Dec 15, 2023
1 parent f14e7fd commit 3bc604d
Show file tree
Hide file tree
Showing 20 changed files with 275 additions and 83 deletions.
8 changes: 4 additions & 4 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ Additionally, this guide uses the following values that should be replaced in yo
// The actual value used instead should be a URL that will be interpreted by your application.
redirectUris = "urn:ietf:wg:oauth:2.0:oob"

// This is equal to the full range of scopes currently supported by BigBone.
// This is equal to the full range of non-admin scopes currently supported by BigBone.
// Instead of this, you should request as little as possible for your application.
scope = Scope()
fullScope = Scope(Scope.READ.ALL, Scope.WRITE.ALL, Scope.PUSH.ALL)
```

## Registering an App
Expand All @@ -46,7 +46,7 @@ val client: MastodonClient = MastodonClient.Builder(instanceHostname).build()
val appRegistration = client.apps.createApp(
clientName = "bigbone-sample-app",
redirectUris = "urn:ietf:wg:oauth:2.0:oob",
scope = Scope(),
scope = fullScope,
website = "https://example.org/"
).execute()
```
Expand All @@ -64,7 +64,7 @@ try {
AppRegistration appRegistration=client.apps().createApp(
"bigbone-sample-app",
"urn:ietf:wg:oauth:2.0:oob",
new Scope(),
fullScope,
"https://example.org/"
).execute();
} catch (BigBoneRequestException e) {
Expand Down
4 changes: 2 additions & 2 deletions bigbone-rx/src/main/kotlin/social/bigbone/rx/RxAppMethods.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ class RxAppMethods(client: MastodonClient) {
* @param clientName A name for your application
* @param redirectUris Where the user should be redirected after authorization.
* @param website A URL to the homepage of your app, defaults to null.
* @param scope Space separated list of scopes. Defaults to all scopes.
* @param scope Space separated list of scopes. Defaults to null, which is interpreted as requesting full "read" scope.
* @see <a href="https://docs.joinmastodon.org/methods/apps/#create">Mastodon apps API methods #create</a>
*/
@JvmOverloads
fun createApp(
clientName: String,
redirectUris: String,
website: String? = null,
scope: Scope = Scope(Scope.Name.ALL)
scope: Scope? = null
): Single<Application> = Single.fromCallable {
appMethods.createApp(clientName, redirectUris, website, scope).execute()
}
Expand Down
14 changes: 10 additions & 4 deletions bigbone-rx/src/main/kotlin/social/bigbone/rx/RxOAuthMethods.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,24 @@ class RxOAuthMethods(client: MastodonClient) {
* @param clientSecret The client secret, obtained during app registration.
* @param redirectUri Set a URI to redirect the user to. Must match one of the redirect_uris declared during app registration.
* @param code A user authorization code, obtained via the URL received from getOAuthUrl()
* @param scope Requested OAuth scopes. Must be equal to the scope requested from the user while obtaining [code].
* If not provided, defaults to read.
* @see <a href="https://docs.joinmastodon.org/methods/oauth/#token">Mastodon oauth API methods #token</a>
*/
@JvmOverloads
fun getUserAccessTokenWithAuthorizationCodeGrant(
clientId: String,
clientSecret: String,
redirectUri: String,
code: String
code: String,
scope: Scope? = null
): Single<Token> = Single.fromCallable {
oAuthMethods.getUserAccessTokenWithAuthorizationCodeGrant(
clientId,
clientSecret,
redirectUri,
code
code,
scope
).execute()
}

Expand Down Expand Up @@ -100,7 +105,8 @@ class RxOAuthMethods(client: MastodonClient) {
* @param redirectUri Set a URI to redirect the user to.
* @param username The Mastodon account username.
* @param password The Mastodon account password.
* @param scope Requested OAuth scopes
* @param scope Requested OAuth scopes. Must be a subset of scopes declared during app registration.
* If not provided, defaults to read.
* @see <a href="https://docs.joinmastodon.org/methods/oauth/#token">Mastodon oauth API methods #token</a>
*/
@JvmOverloads
Expand All @@ -110,7 +116,7 @@ class RxOAuthMethods(client: MastodonClient) {
redirectUri: String,
username: String,
password: String,
scope: Scope = Scope(Scope.Name.READ)
scope: Scope? = null
): Single<Token> = Single.fromCallable {
oAuthMethods.getUserAccessTokenWithPasswordGrant(
clientId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package social.bigbone

import social.bigbone.api.Scope

class TestConstants {
companion object {
const val REST_API_HOSTNAME = "localhost"
Expand All @@ -15,5 +17,7 @@ class TestConstants {
const val USER2_USERNAME = "user2"
const val USER2_EMAIL = "[email protected]"
const val USER2_PASSWORD = "user2abcdef"

val fullScope = Scope(Scope.READ.ALL, Scope.WRITE.ALL, Scope.PUSH.ALL)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package social.bigbone

import social.bigbone.api.Scope
import social.bigbone.api.entity.Application
import social.bigbone.api.entity.MediaAttachment
import social.bigbone.api.entity.Token
Expand All @@ -26,7 +25,7 @@ object TestHelpers {

fun createApp(appName: String): Application {
val client = getTrustAllClient()
return client.apps.createApp(appName, TestConstants.REDIRECT_URI, null, Scope(Scope.Name.ALL)).execute()
return client.apps.createApp(appName, TestConstants.REDIRECT_URI, null, TestConstants.fullScope).execute()
}

fun getAppToken(application: Application): Token {
Expand All @@ -35,7 +34,7 @@ object TestHelpers {
clientId = application.clientId!!,
clientSecret = application.clientSecret!!,
redirectUri = TestConstants.REDIRECT_URI,
scope = Scope(Scope.Name.ALL)
scope = TestConstants.fullScope
).execute()
}

Expand All @@ -44,7 +43,7 @@ object TestHelpers {
return client.oauth.getUserAccessTokenWithPasswordGrant(
clientId = application.clientId!!,
clientSecret = application.clientSecret!!,
scope = Scope(Scope.Name.ALL),
scope = TestConstants.fullScope,
redirectUri = TestConstants.REDIRECT_URI,
username = username,
password = password
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import social.bigbone.MastodonClient
import social.bigbone.TestConstants
import social.bigbone.api.Scope
import social.bigbone.api.entity.Application
import social.bigbone.api.entity.Token

Expand Down Expand Up @@ -40,7 +39,7 @@ class V300StatusMethodsIntegrationTest {
val client = MastodonClient.Builder(TestConstants.REST_API_HOSTNAME)
.withTrustAllCerts()
.build()
return client.apps.createApp(TestConstants.USER2_APP_NAME, TestConstants.REDIRECT_URI, null, Scope(Scope.Name.ALL)).execute()
return client.apps.createApp(TestConstants.USER2_APP_NAME, TestConstants.REDIRECT_URI, null, TestConstants.fullScope).execute()
}

private fun getAppToken(application: Application): Token {
Expand All @@ -51,7 +50,7 @@ class V300StatusMethodsIntegrationTest {
clientId = application.clientId!!,
clientSecret = application.clientSecret!!,
redirectUri = TestConstants.REDIRECT_URI,
scope = Scope(Scope.Name.ALL)
scope = TestConstants.fullScope
).execute()
}

Expand All @@ -62,7 +61,7 @@ class V300StatusMethodsIntegrationTest {
return client.oauth.getUserAccessTokenWithPasswordGrant(
clientId = application.clientId!!,
clientSecret = application.clientSecret!!,
scope = Scope(Scope.Name.ALL),
scope = TestConstants.fullScope,
redirectUri = TestConstants.REDIRECT_URI,
username = username,
password = password
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import social.bigbone.MastodonClient
import social.bigbone.TestConstants
import social.bigbone.api.Scope
import social.bigbone.api.entity.Application
import social.bigbone.api.entity.Token

Expand Down Expand Up @@ -40,7 +39,7 @@ class V402StatusMethodsIntegrationTest {
val client = MastodonClient.Builder(TestConstants.REST_API_HOSTNAME)
.withTrustAllCerts()
.build()
return client.apps.createApp(TestConstants.USER2_APP_NAME, TestConstants.REDIRECT_URI, null, Scope(Scope.Name.ALL)).execute()
return client.apps.createApp(TestConstants.USER2_APP_NAME, TestConstants.REDIRECT_URI, null, TestConstants.fullScope).execute()
}

private fun getAppToken(application: Application): Token {
Expand All @@ -51,7 +50,7 @@ class V402StatusMethodsIntegrationTest {
clientId = application.clientId!!,
clientSecret = application.clientSecret!!,
redirectUri = TestConstants.REDIRECT_URI,
scope = Scope(Scope.Name.ALL)
scope = TestConstants.fullScope
).execute()
}

Expand All @@ -62,7 +61,7 @@ class V402StatusMethodsIntegrationTest {
return client.oauth.getUserAccessTokenWithPasswordGrant(
clientId = application.clientId!!,
clientSecret = application.clientSecret!!,
scope = Scope(Scope.Name.ALL),
scope = TestConstants.fullScope,
redirectUri = TestConstants.REDIRECT_URI,
username = username,
password = password
Expand Down
Loading

0 comments on commit 3bc604d

Please sign in to comment.