Skip to content

Commit f3b4f58

Browse files
Releasing version 65.102.1
Releasing version 65.102.1
2 parents 907df66 + 0ea5770 commit f3b4f58

File tree

59 files changed

+2595
-482
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+2595
-482
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66

7+
## 65.102.1 - 2025-10-21
8+
### Added
9+
- Support for LDAP schema version RFC2307bis when creating and updating mount targets in the File Storage service
10+
- Support for Helm Critical Resource Protection (HCRP) in the DevOps Deploy service
11+
- Support for parameterized pipelines in the Data Science service
12+
- Support for Zero Trust Packet Routing (ZPR) security attributes in the Streaming service
13+
- Support for configurable version upgrade policies in the MySQL HeatWave service
14+
- Support for 26ai version in the Exadata Fleet Update service
15+
716
## 65.102.0 - 2025-10-07
817
### Added
918
- Support for OCI Internet of Things (OCI IoT) service

Makefile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,7 @@ $(TARGETS_TESTFILTERED): testfiltered-%:%
7676
@(cd $< && go test -parallel 5 -timeout 1200s -v -run $(TEST_NAME))
7777

7878
$(TARGETS_INTEG_TEST): test-%:%
79-
@(cd $< && go test -parallel 5 -timeout 1200s -v)
80-
@echo "cleaning up tests"
81-
@(cd $< && GO_INTEGRATION_CLEANUP=true go test -run ^TestComputeClient_CleanupResources -v)
79+
@(./scripts/run-integ-and-cleanup.sh)
8280

8381
$(TARGETS_CLEAN): clean-%:%
8482
@echo "cleaning $<"

common/auth/federation_client.go

100644100755
Lines changed: 187 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,188 @@ func newStaticFederationClient(sessionToken string, supplier sessionKeySupplier)
133133
}, nil
134134
}
135135

136+
// oAuth2FederationClient retrieves a security token from the scoped OAuth endpoint in Auth Service
137+
type oAuth2FederationClient struct {
138+
sessionKeySupplier sessionKeySupplier
139+
authClientKeyProvider common.KeyProvider
140+
authClient *common.BaseClient
141+
securityToken securityToken
142+
lastRefresh time.Time
143+
scope string
144+
targetCompartment string
145+
mux sync.Mutex
146+
}
147+
148+
var OAuthTokenStaleWindow = 20 * time.Minute
149+
150+
// newOAuth2FederationClient creates a new oAuth2FederationClient from the provided configProvider and Auth request parameters
151+
func newOAuth2FederationClient(configProvider common.ConfigurationProvider, scope string, targetCompartment string, sessionKeySupplier sessionKeySupplier) (federationClient, error) {
152+
client := &oAuth2FederationClient{}
153+
client.sessionKeySupplier = sessionKeySupplier
154+
region, err := configProvider.Region()
155+
if err != nil {
156+
return nil, fmt.Errorf("failed to build OAuth Federation Client: %s", err.Error())
157+
}
158+
authClient := newAuthClient(common.StringToRegion(region), configProvider, "v1/oauth2/scoped")
159+
client.authClient = authClient
160+
client.authClientKeyProvider = configProvider
161+
client.scope = scope
162+
client.targetCompartment = targetCompartment
163+
return client, nil
164+
}
165+
166+
// KeyID calls the KeyID method of the auth provider given to the federation client
167+
func (c *oAuth2FederationClient) KeyID() (string, error) {
168+
return c.authClientKeyProvider.KeyID()
169+
}
170+
171+
// PrivateRSAKey calls the PrivateRSAKey method of the auth provider given to the federation client
172+
func (c *oAuth2FederationClient) PrivateRSAKey() (*rsa.PrivateKey, error) {
173+
return c.authClientKeyProvider.PrivateRSAKey()
174+
}
175+
176+
func (c *oAuth2FederationClient) GetClaim(key string) (interface{}, error) {
177+
c.mux.Lock()
178+
defer c.mux.Unlock()
179+
180+
if err := c.renewKeyAndSecurityTokenIfNotValid(); err != nil {
181+
return nil, err
182+
}
183+
return c.securityToken.GetClaim(key)
184+
}
185+
186+
// isTokenStale returns true if the JWT token is older than OAuthTokenStaleWindow
187+
func (c *oAuth2FederationClient) isTokenStale() bool {
188+
return c.lastRefresh.IsZero() || time.Now().After(c.lastRefresh.Add(OAuthTokenStaleWindow))
189+
}
190+
191+
func (c *oAuth2FederationClient) renewKeyAndSecurityTokenIfNotValid() (err error) {
192+
return c.renewSecurityTokenIfNotValid()
193+
}
194+
195+
func (c *oAuth2FederationClient) renewSecurityTokenIfNotValid() (err error) {
196+
197+
// Get a new token if this one is stale (or nil), even if it is still valid
198+
if c.securityToken == nil || c.isTokenStale() {
199+
if err = c.renewSecurityToken(); err != nil {
200+
if c.securityToken != nil && c.securityToken.Valid() {
201+
// Token is stale but still valid. We failed to get a new token
202+
// but we can still use the old one
203+
common.Debugln("failed to refresh OAuth token. Using valid cached token")
204+
return nil
205+
}
206+
207+
return fmt.Errorf("failed to refresh token: %s", err.Error())
208+
}
209+
}
210+
211+
// Token exists and is not stale,
212+
// or token was stale and a new one was retrieved
213+
return nil
214+
}
215+
216+
func (c *oAuth2FederationClient) renewSecurityToken() (err error) {
217+
if err = c.sessionKeySupplier.Refresh(); err != nil {
218+
return fmt.Errorf("failed to refresh session key: %s", err.Error())
219+
}
220+
221+
common.Logf("Renewing security token at: %v\n", time.Now().Format("15:04:05.000"))
222+
if newToken, err := c.getSecurityToken(); err != nil {
223+
return fmt.Errorf("failed to get security token: %s", err.Error())
224+
} else {
225+
// only update token if a new one was retrieved.
226+
c.lastRefresh = time.Now()
227+
c.securityToken = newToken
228+
}
229+
230+
common.Logf("Security token renewed at: %v\n", time.Now().Format("15:04:05.000"))
231+
232+
return nil
233+
234+
}
235+
236+
func (c *oAuth2FederationClient) getSecurityToken() (securityToken, error) {
237+
var err error
238+
var httpRequest http.Request
239+
var httpResponse *http.Response
240+
defer common.CloseBodyIfValid(httpResponse)
241+
for retry := 0; retry < 3; retry++ {
242+
request := c.makeOAuthFederationRequest()
243+
244+
if httpRequest, err = common.MakeDefaultHTTPRequestWithTaggedStruct(http.MethodPost, "", request); err != nil {
245+
return nil, fmt.Errorf("failed to make http request: %s", err.Error())
246+
}
247+
248+
if httpResponse, err = c.authClient.Call(context.Background(), &httpRequest); err == nil {
249+
break
250+
}
251+
// Don't retry on 4xx errors
252+
if httpResponse != nil && httpResponse.StatusCode >= 400 && httpResponse.StatusCode <= 499 {
253+
return nil, fmt.Errorf("error %s returned by auth service: %s", httpResponse.Status, err.Error())
254+
}
255+
nextDuration := time.Duration(1000.0*(math.Pow(2.0, float64(retry)))) * time.Millisecond
256+
time.Sleep(nextDuration)
257+
}
258+
if err != nil {
259+
return nil, fmt.Errorf("failed to call: %s", err.Error())
260+
}
261+
262+
response := oAuthFederationResponse{}
263+
if err = common.UnmarshalResponse(httpResponse, &response); err != nil {
264+
return nil, fmt.Errorf("failed to unmarshal the response: %s", err.Error())
265+
}
266+
267+
return newPrincipalToken(response.Token.Token)
268+
269+
}
270+
271+
type oAuthFederationRequest struct {
272+
OAuthFederationDetails `contributesTo:"body"`
273+
}
274+
275+
// OAuthFederationDetails Scoped Oauth federation details
276+
// The scope type should correspond to the type of config provider used to create
277+
// the OAuth Federation Client
278+
type OAuthFederationDetails struct {
279+
Scope string `mandatory:"true" json:"scope,omitempty"`
280+
PublicKey string `mandatory:"true" json:"public_key,omitempty"`
281+
TargetCompartment string `mandatory:"true" json:"target_compartment,omitempty"`
282+
}
283+
284+
type oAuthFederationResponse struct {
285+
Token `presentIn:"body"`
286+
}
287+
288+
func (c *oAuth2FederationClient) makeOAuthFederationRequest() *oAuthFederationRequest {
289+
publicKey := sanitizeCertificateString(string(c.sessionKeySupplier.PublicKeyPemRaw()))
290+
details := OAuthFederationDetails{
291+
Scope: c.scope,
292+
PublicKey: publicKey,
293+
TargetCompartment: c.targetCompartment,
294+
}
295+
return &oAuthFederationRequest{details}
296+
}
297+
298+
func (c *oAuth2FederationClient) PrivateKey() (*rsa.PrivateKey, error) {
299+
c.mux.Lock()
300+
defer c.mux.Unlock()
301+
302+
if err := c.renewSecurityTokenIfNotValid(); err != nil {
303+
return nil, err
304+
}
305+
return c.sessionKeySupplier.PrivateKey(), nil
306+
}
307+
308+
func (c *oAuth2FederationClient) SecurityToken() (token string, err error) {
309+
c.mux.Lock()
310+
defer c.mux.Unlock()
311+
312+
if err = c.renewSecurityTokenIfNotValid(); err != nil {
313+
return "", err
314+
}
315+
return c.securityToken.String(), nil
316+
}
317+
136318
// x509FederationClient retrieves a security token from Auth service.
137319
type x509FederationClient struct {
138320
tenancyID string
@@ -151,7 +333,7 @@ func newX509FederationClient(region common.Region, tenancyID string, leafCertifi
151333
intermediateCertificateRetrievers: intermediateCertificateRetrievers,
152334
}
153335
client.sessionKeySupplier = newSessionKeySupplier()
154-
authClient := newAuthClient(region, client)
336+
authClient := newAuthClient(region, client, "v1/x509")
155337

156338
var err error
157339

@@ -176,7 +358,7 @@ func newX509FederationClientWithCerts(region common.Region, tenancyID string, le
176358
intermediateCertificateRetrievers: intermediateRetrievers,
177359
}
178360
client.sessionKeySupplier = newSessionKeySupplier()
179-
authClient := newAuthClient(region, client)
361+
authClient := newAuthClient(region, client, "v1/x509")
180362

181363
var err error
182364

@@ -194,15 +376,16 @@ var (
194376
bodyHeaders = []string{"content-length", "content-type", "x-content-sha256"}
195377
)
196378

197-
func newAuthClient(region common.Region, provider common.KeyProvider) *common.BaseClient {
379+
func newAuthClient(region common.Region, provider common.KeyProvider, authBasePath string) *common.BaseClient {
198380
signer := common.RequestSigner(provider, genericHeaders, bodyHeaders)
199381
client := common.DefaultBaseClientWithSigner(signer)
382+
200383
if regionURL, ok := os.LookupEnv("OCI_SDK_AUTH_CLIENT_REGION_URL"); ok {
201384
client.Host = regionURL
202385
} else {
203386
client.Host = region.Endpoint("auth")
204387
}
205-
client.BasePath = "v1/x509"
388+
client.BasePath = authBasePath
206389

207390
if common.GlobalAuthClientCircuitBreakerSetting != nil {
208391
client.Configuration.CircuitBreaker = common.NewCircuitBreaker(common.GlobalAuthClientCircuitBreakerSetting)

0 commit comments

Comments
 (0)