aws / aws/aws-sdk-java-v2

Cognito: support for partial UpdateUserPoolClient calls

Aperta
#5,221 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub
feature-request p2 service-api service:cognito
Lingua principale
Java
Stelle
2.6k
Fork
1k
Merge medio
2g 9h
PR unite (30g)
51

Descrizione

### Describe the feature

The `UpdateUserPoolClient` should support partial updates instead of having to provide every single parameter in the request.

### Use Case

Currently, the process to update a user pool client through the SDK is very cumbersome. For example, if we only want to update the `callbackURLs` on an existing user pool client, we have to pass every single property with the *existing* value to the `UpdateUserPoolClientRequest`. This is because Cognito [doesn't support partial updates](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPoolClient.html):

> If you don't provide a value for an attribute, Amazon Cognito sets it to its default value.

```kotlin
import software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient
import software.amazon.awssdk.services.cognitoidentityprovider.model.DescribeUserPoolClientRequest
import software.amazon.awssdk.services.cognitoidentityprovider.model.UpdateUserPoolClientRequest

class CognitoClient(
private val cognitoConfig: CognitoConfig,
private val cognitoClient: CognitoIdentityProviderClient,
) {
// redacted other methods

fun addCallbackUrlToAppClient(clientId: String, callbackUrl: String) {
val describeUserPoolClientRequest = DescribeUserPoolClientRequest.builder()
.clientId(clientId)
.userPoolId(cognitoConfig.userPoolId)
.build()

val existingUserPoolClient = cognitoClient
.describeUserPoolClient(describeUserPoolClientRequest)
.userPoolClient()

val existingCallbackUrls = existingUserPoolClient.callbackURLs()

if (existingCallbackUrls.contains(callbackUrl)) {
logger.info("Callback URL $callbackUrl already exists for client $clientId, skipping.")
return
}

// We need to copy the list because it's immutable.
val updatedCallbackUrls = existingCallbackUrls.toMutableList()
updatedCallbackUrls.add(callbackUrl)

/**
* From the Cognito docs: "WARNING - If you don't provide a value for an attribute,
* Amazon Cognito sets it to its default value."
*
* So here we are, setting all the attributes to their already existing values.
*/
val updateRequest = UpdateUserPoolClientRequest.builder()
.accessTokenValidity(existingUserPoolClient.accessTokenValidity())
.allowedOAuthFlows(existingUserPoolClient.allowedOAuthFlows())
.allowedOAuthFlowsUserPoolClient(existingUserPoolClient.allowedOAuthFlowsUserPoolClient())
.allowedOAuthScopes(existingUserPoolClient.allowedOAuthScopes())
.analyticsConfiguration(existingUserPoolClient.analyticsConfiguration())
.authSessionValidity(existingUserPoolClient.authSessionValidity())
// This is the only field we're _actually_ changing
.callbackURLs(updatedCallbackUrls)
.clientId(existingUserPoolClient.clientId())
.clientName(existingUserPoolClient.clientName())
.defaultRedirectURI(existingUserPoolClient.defaultRedirectURI())
.enablePropagateAdditionalUserContextData(existingUserPoolClient.enablePropagateAdditionalUserContextData())
.enableTokenRevocation(existingUserPoolClient.enableTokenRevocation())
.explicitAuthFlows(existingUserPoolClient.explicitAuthFlows())
.idTokenValidity(existingUserPoolClient.idTokenValidity())
.logoutURLs(existingUserPoolClient.logoutURLs())
.preventUserExistenceErrors(existingUserPoolClient.preventUserExistenceErrors())
.readAttributes(existingUserPoolClient.readAttributes())
.refreshTokenValidity(existingUserPoolClient.refreshTokenValidity())
.supportedIdentityProviders(existingUserPoolClient.supportedIdentityProviders())
.tokenValidityUnits(existingUserPoolClient.tokenValidityUnits())
.userPoolId(existingUserPoolClient.userPoolId())
.writeAttributes(existingUserPoolClient.writeAttributes())
.build()

cognitoClient.updateUserPoolClient(updateRequest)

logger.info("Successfully added callback URL $callbackUrl to Cognito App Client $clientId")
}
}
```

### Proposed Solution

This probably will need updates on the Cognito service side. However, I do think it would be nice if the SDK could provide a convenience method in the meantime. I guess something like:

```kotlin
import software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient
import software.amazon.awssdk.services.cognitoidentityprovider.model.DescribeUserPoolClientRequest
import software.amazon.awssdk.services.cognitoidentityprovider.model.UpdateUserPoolClientRequest

class CognitoClient(
private val cognitoConfig: CognitoConfig,
private val cognitoClient: CognitoIdentityProviderClient,
) {
// redacted other methods

fun addCallbackUrlToAppClient(clientId: String, callbackUrl: String) {
val describeUserPoolClientRequest = DescribeUserPoolClientRequest.builder()
.clientId(clientId)
.userPoolId(cognitoConfig.userPoolId)
.build()

val existingUserPoolClient = cognitoClient
.describeUserPoolClient(describeUserPoolClientRequest)
.userPoolClient()

val existingCallbackUrls = existingUserPoolClient.callbackURLs()

if (existingCallbackUrls.contains(callbackUrl)) {
logger.info("Callback URL $callbackUrl already exists for client $clientId, skipping.")
return
}

// We need to copy the list because it's immutable.
val updatedCallbackUrls = existingCallbackUrls.toMutableList()
updatedCallbackUrls.add(callbackUrl)

val updateRequest = UpdateUserPoolClientRequest.builder()
.callbackURLs(updatedCallbackUrls)
.clientId(existingUserPoolClient.clientId())
.build()

cognitoClient.updateUserPoolClient(updateRequest, true)

logger.info("Successfully added callback URL $callbackUrl to Cognito App Client $clientId")
}
}
```

Note that `updateUserPoolClient` now takes a second parameter. This parameter could be named something like `keepExistingParameters` and default to `false`, so it's not a breaking change. If `true`, it could get the existing user pool (either by doing a `describeUserPoolClient` under the hood or require an existing `UserPoolClientType` to be passed).

### Other Information

Related Cognito docs: https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPoolClient.html

### Acknowledgements

- [ ] I may be able to implement this feature request
- [ ] This feature might incur a breaking change

### AWS Java SDK version used

2.25.50

### JDK version used

17.0.10

### Operating System and version

macOS 14.4.1

Guida per i contributori

Apri la guida per i contributori

Direzione di ricerca

Iniziare con la documentazione dell’API AWS UpdateUserPoolClient e con gli entry point denominati UpdateUserPoolClientRequest, updateUserPoolClient e DescribeUserPoolClient. Confrontare il comportamento proposto di keepExistingParameters con il contratto esistente dell’SDK e determinare come gli aggiornamenti parziali debbano rimanere retrocompatibili; il lavoro richiede un design concordato e la relativa validazione.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
aws, java, kotlin
Ambito
authentication, cloud
Tipo di issue
Funzionalità
Difficoltà
5/5
Tempo stimato
Più di una settimana
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
35/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.