-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add authentication support for ACR #19926
Conversation
/** | ||
* A token cache that supports caching a token and refreshing it. | ||
*/ | ||
class AccessTokenCache { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally this class can be exposed via the experimental package and we can consume it.
@g2vinay - I will sync up with you on this. #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per the offline discussion:
Given that ACR has a separate sts service and issues its own independent tokens with custom expiry.
It makes sense to have independent caching logic for it, as it has the potential to evolve in the future if we choose to cache in the ACR tokens per scope. (That'd be a great optimization from a performance perspective if we pull it off).
The AAD token caching logic in azure-core can evolve too in the future and will give priority to AAD tokens specifically. So, the two implementations are not directly tied together, and having independent caches, allows to optimize and augment the caching logic best for ACR and AAD respectively.
Seems both the caches are implementation details, once ACR caching logic has stabilized and evolved we can always look into merging them together without breaking public API, if possible given their mature state at that time.
#Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import reactor.core.publisher.Mono; | ||
|
||
/** An instance of this class provides access to all the operations defined in AccessTokensService. */ | ||
public final class AccessTokensImpl { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public [](start = 0, length = 6)
Why do we generate these classes as public? #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to hand author the generated files due to the discrepancy between www-encoded form not correctly supported. Also, I could not use the builder pattern since this class is a hierarchial pattern and has only one builder. And it needed the policy that had to be added to the builder to consume this class. Unfortunately ACR's STS goes through the same rest endpoints. Let me know if there is a better way to do it.
In reply to: 596415910 [](ancestors = 596415910)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These classes are generated as public
since Java classes cannot be accessible across package boundaries without either being protected
or public
. #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pallavit could you please file a bug in autorest.java repo with steps to reproduce and the expected code that should be generated? Ideally, we should not modify any generated code manually as it would be overwritten when we regenerate this code. #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There already is a bug and @jianghaolu is aware of it.
In reply to: 597954987 [](ancestors = 597954987)
autorest --java --use=C:/work/autorest.java | ||
``` | ||
|
||
### Code generation settings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file and the swagger will change. The swagger is still being worked upon. #Resolved
* Request Header: {Bearer acrTokenAccess} | ||
* | ||
*/ | ||
public class ContainerRegistryCredentialsPolicy implements HttpPipelinePolicy { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally, we want to eagerly mark classes as final
, equivalent to sealed
in .NET. It's a non-breaking change to remove final
in the future if required but marking as final
is breaking #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...om/azure/containers/containerregistry/authentication/ContainerRegistryCredentialsPolicy.java
Outdated
Show resolved
Hide resolved
import reactor.core.publisher.Mono; | ||
|
||
/** An instance of this class provides access to all the operations defined in AccessTokensService. */ | ||
public final class AccessTokensImpl { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These classes are generated as public
since Java classes cannot be accessible across package boundaries without either being protected
or public
. #Resolved
package com.azure.containers.containerregistry.authentication; | ||
|
||
import com.azure.core.credential.AccessToken; | ||
import com.azure.core.http.*; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Our guidelines don't allow *
imports #Resolved
7cbec67
to
c052370
Compare
d43ea1e
to
a1afb2f
Compare
/** | ||
* This package contains classes for the container registry project. | ||
*/ | ||
package com.azure.containers.containerregistry.authentication; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any classes in this package. Is this package-info required? #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missed this. I moved all the files from here to the implementation package.
In reply to: 597948739 [](ancestors = 597948739)
Mono<AccessToken> fallback; | ||
|
||
Supplier<Mono<AccessToken>> tokenSupplier = () -> { | ||
Objects.requireNonNull(this.tokenRequestContext); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't throw an exception when returning a reactive publisher (Mono/Flux). Instead return Mono.error()
or Flux.error()
#Resolved
|
||
private Supplier<Mono<? extends AccessToken>> retrieveToken(ContainerRegistryTokenRequestContextImpl tokenRequestContext) { | ||
return () -> { | ||
try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole supplier should be wrapped with Mono.defer() to evaluate the need to refresh at subscription-time instead of at assembly-time. #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The caller actually does that - retrieveToken call just above this method. Since this is a private method chose not to do it.
In reply to: 597950212 [](ancestors = 597950212)
import reactor.core.publisher.Mono; | ||
|
||
/** An instance of this class provides access to all the operations defined in AccessTokensService. */ | ||
public final class AccessTokensImpl { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pallavit could you please file a bug in autorest.java repo with steps to reproduce and the expected code that should be generated? Ideally, we should not modify any generated code manually as it would be overwritten when we regenerate this code. #Resolved
* <p>Step5: GET /api/v1/acr/repositories | ||
* Request Header: {Bearer acrTokenAccess}</p> | ||
*/ | ||
public class ContainerRegistryCredentialsPolicy implements HttpPipelinePolicy { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally, we make all pipeline policies public so that users add the policy to their own HTTP pipeline. #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The policy is not public - just because we are still ironing out what is the right handshake with experimental package. Having said that, this policy may not be public even in future - since its a convenience layer added for the customer.
In reply to: 597957262 [](ancestors = 597957262)
* Token credentials representing the container registry refresh token. | ||
* This token is unique per registry operation. | ||
*/ | ||
class ContainerRegistryTokenCredentialImpl { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed offline, will this type be implementing TokenCredential
? #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it may. As of now since the surface is non-public, we have the flexibility of changing it in future.
In reply to: 597957584 [](ancestors = 597957584)
/** | ||
* A token request context associated with a given container registry token. | ||
*/ | ||
class ContainerRegistryTokenRequestContextImpl { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need to append Impl
to class names if they are already in implementation package. #Resolved
@@ -0,0 +1,123 @@ | |||
// Copyright (c) Microsoft Corporation. All rights reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this class handwritten? The license header doesn't have this line // Code generated by Microsoft (R) AutoRest Code Generator.
which is generally included for all generated files. #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, as mentioned in another file, a bug tracking this already exists.
In reply to: 597960498 [](ancestors = 597960498)
|
||
## Contributing | ||
<Add contributing steps> | ||
<Instructions on how to contribute>. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be able to copy the template project's section for this #Resolved
// Licensed under the MIT License. | ||
|
||
/** | ||
* This package contains classes for the container registry project. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* This package contains classes for the container registry project. | |
* This package contains authentication classes used by Azure Container Registry. | |
``` #Resolved |
@@ -2,5 +2,6 @@ | |||
// Licensed under the MIT License. | |||
|
|||
module com.azure.containers.containerregistry { | |||
requires transitive com.azure.core; | |||
exports com.azure.containers.containerregistry; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want the classes in com.azure.containers.containerregistry.authentication
to be available outside of the project you'll need to add it as an export here. #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3495ee9
to
e287bcd
Compare
e287bcd
to
7559df9
Compare
/check-enforcer evaluate |
/check-enforcer evaluate |
New API Path added "datawarehousequeries" in sqlpool (Azure#19926) * Path datawarehousequeries added in sqlpool * Resolved Conflict - removed space * Changes in definitions * Changes in example-getdatawarehousequeries.json * added object in sqlpool * Updated datawarehousequeries json * modified sqlpool definitions * Removed properties in example json * added Removed items * added response in example json for dataWarehouseQueries * Added properties in definitions * updated mismatch type * modifications in id path * Properties changes * changed Value to Properties * properties to value changes * removed Nextlink * Removed array * updated description * Added type in response * chnages in responses * changes in readme * Null Changes * Changes in Readme added Datawarehousequeries * added missing tag in batch * Changed Value Object * Reversed type changes * Camel case changes * Camel Changes * Removed Extra Value Properties * Added Properties * Description Changes * resourceClass values * Added Custom Words Co-authored-by: VamshiKrishna Chirra (Quadrant Resource) <vamshikrishna.chirra@quadrantresource.com>
ACR follows a challenge based authorization and functions as follows
For example
GET {url} /api/v1/acr/repositories translates into the following calls.
Step1: GET /api/v1/acr/repositories
Return Header: 401: www-authenticate header - Bearer realm="{url}",service="{serviceName}",scope="{scope}",error="invalid_token".
Step2: Parse the serviceName, scope from the service.
Step3: POST /api/oauth2/exchange
Request Body : {service, scope, grant-type, aadToken with ARM scope}
Response Body: {acrRefreshToken}
Step4: POST /api/oauth2/token
Request Body: {acrRefreshToken, scope, grant-type}
Response Body: {acrAccessToken}
Step5: GET /api/v1/acr/repositories
Request Header: {Bearer acrTokenAccess}
In order to prevent user from having to do this tedious process we have decided to build a convenience layer on ACR - that does this under the hood by exposing an ACR specific policy.