Skip to content

Commit

Permalink
add observers for oauth tokenconfig
Browse files Browse the repository at this point in the history
  • Loading branch information
stlaz committed Apr 21, 2020
1 parent dce79b9 commit 08abc5f
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ func NewConfigObserver(
infrastructure.ObserveAPIServerURL,
oauth.ObserveIdentityProviders,
oauth.ObserveTemplates,
oauth.ObserveTokenConfig,
routersecret.ObserveRouterSecret,
} {
oauthServerObservers = append(oauthServerObservers,
Expand Down
106 changes: 106 additions & 0 deletions pkg/operator2/configobservation/oauth/observe_tokenconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package oauth

import (
"k8s.io/klog"

"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"

"github.com/openshift/library-go/pkg/operator/configobserver"
"github.com/openshift/library-go/pkg/operator/events"

"github.com/openshift/cluster-authentication-operator/pkg/operator2/configobservation"
)

const defaultAccessTokenMaxAgeSeconds = float64(86400) // a day

func ObserveTokenConfig(genericlisters configobserver.Listers, recorder events.Recorder, previouslyObservedConfig map[string]interface{}) (map[string]interface{}, []error) {
tokenConfigPath := []string{"oauthConfig", "tokenConfig"}
listers := genericlisters.(configobservation.Listers)
errs := []error{}

currentTokenConfig, _, err := unstructured.NestedMap(previouslyObservedConfig, tokenConfigPath...)
if err != nil {
return previouslyObservedConfig, append(errs, err)
}

currentAccessTokenMaxAgeSeconds, _, err := unstructured.NestedFloat64(currentTokenConfig, "accessTokenMaxAgeSeconds")
if err != nil {
errs = append(errs, err)
}

currentAccessTokenInactivityTimeoutSeconds, _, err := unstructured.NestedFieldCopy(currentTokenConfig, "accessTokenInactivityTimeoutSeconds")
if err != nil {
errs = append(errs, err)
}
var currentAccessTokenInactivityTimeoutSecondsFloat *float64
if currentAccessTokenInactivityTimeoutSeconds != nil {
if f, ok := currentAccessTokenInactivityTimeoutSeconds.(float64); ok {
currentAccessTokenInactivityTimeoutSecondsFloat = &f
}
}

observedConfig := map[string]interface{}{}
oauthConfig, err := listers.OAuthLister.Get("cluster")
if errors.IsNotFound(err) {
klog.Warning("oauth.config.openshift.io/cluster: not found")
return map[string]interface{}{
"oauthConfig": map[string]interface{}{
"tokenConfig": map[string]interface{}{
"accessTokenMaxAgeSeconds": defaultAccessTokenMaxAgeSeconds,
},
},
}, nil
} else if err != nil {
return previouslyObservedConfig, append(errs, err)
}

observedAccessTokenMaxAgeSeconds := float64(oauthConfig.Spec.TokenConfig.AccessTokenMaxAgeSeconds)
if observedAccessTokenMaxAgeSeconds == 0 {
observedAccessTokenMaxAgeSeconds = defaultAccessTokenMaxAgeSeconds
}

observedTokenConfigFieldMap := map[string]interface{}{
"accessTokenMaxAgeSeconds": observedAccessTokenMaxAgeSeconds,
}

observedAccessTokenInactivityTimeoutSeconds := convertAccessTokenInactivityTimeout(oauthConfig.Spec.TokenConfig.AccessTokenInactivityTimeoutSeconds)
if observedAccessTokenInactivityTimeoutSeconds != nil {
observedTokenConfigFieldMap["accessTokenInactivityTimeoutSeconds"] = *observedAccessTokenInactivityTimeoutSeconds
}

if err := unstructured.SetNestedMap(
observedConfig,
observedTokenConfigFieldMap,
tokenConfigPath...,
); err != nil {
return previouslyObservedConfig, append(errs, err)
}

if !(currentAccessTokenMaxAgeSeconds == observedAccessTokenMaxAgeSeconds) {
recorder.Eventf("ObserveTokenConfig", "accessTokenMaxAgeSeconds changed from %d to %d", currentAccessTokenMaxAgeSeconds, observedAccessTokenMaxAgeSeconds)
}

if !(currentAccessTokenInactivityTimeoutSecondsFloat == observedAccessTokenInactivityTimeoutSeconds) {
recorder.Eventf("ObserveTokenConfig", "accessTokenInactivityTimeoutSeconds changed from %d to %d", currentAccessTokenInactivityTimeoutSecondsFloat, observedAccessTokenInactivityTimeoutSeconds)

}

return observedConfig, errs
}

func convertAccessTokenInactivityTimeout(observedValue int32) *float64 {
var ret *float64
floatVal := float64(observedValue)
switch {
case floatVal == 0:
ret = nil
case floatVal < 0:
zero := float64(0)
ret = &zero
case floatVal > 0:
ret = &floatVal
}

return ret
}
82 changes: 82 additions & 0 deletions pkg/operator2/configobservation/oauth/observe_tokenconfig_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package oauth

import (
"testing"

"k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/client-go/tools/cache"

configv1 "github.com/openshift/api/config/v1"
configlistersv1 "github.com/openshift/client-go/config/listers/config/v1"
"github.com/openshift/library-go/pkg/operator/events"

"github.com/openshift/cluster-authentication-operator/pkg/operator2/configobservation"
)

func TestObserveTokenConfig(t *testing.T) {
tests := []struct {
name string
config *configv1.OAuth
previouslyObservedConfig map[string]interface{}
expected map[string]interface{}
errors []error
}{
{
name: "nil config",
config: nil,
previouslyObservedConfig: map[string]interface{}{},
expected: map[string]interface{}{
"oauthConfig": map[string]interface{}{
"tokenConfig": map[string]interface{}{"accessTokenMaxAgeSeconds": float64(86400)},
},
},
errors: []error{},
},
{
name: "both fields configured",
config: &configv1.OAuth{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster",
},
Spec: configv1.OAuthSpec{
TokenConfig: configv1.TokenConfig{
AccessTokenMaxAgeSeconds: 172800,
AccessTokenInactivityTimeoutSeconds: 300,
},
},
},
previouslyObservedConfig: map[string]interface{}{},
expected: map[string]interface{}{
"oauthConfig": map[string]interface{}{
"tokenConfig": map[string]interface{}{
"accessTokenInactivityTimeoutSeconds": float64(300),
"accessTokenMaxAgeSeconds": float64(172800),
},
},
},
errors: []error{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{})
if tt.config != nil {
if err := indexer.Add(tt.config); err != nil {
t.Fatal(err)
}
}
listers := configobservation.Listers{
OAuthLister: configlistersv1.NewOAuthLister(indexer),
}
got, errs := ObserveTokenConfig(listers, events.NewInMemoryRecorder(t.Name()), tt.previouslyObservedConfig)
if len(errs) > 0 {
t.Errorf("Expected 0 errors, got %v.", len(errs))
}
if !equality.Semantic.DeepEqual(tt.expected, got) {
t.Errorf("result does not match expected config: %s", diff.ObjectDiff(tt.expected, got))
}
})
}
}
40 changes: 0 additions & 40 deletions pkg/operator2/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
"fmt"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
Expand Down Expand Up @@ -42,29 +40,6 @@ func (c *authOperator) handleOAuthConfig(
*corev1.ConfigMap,
error,
) {
oauthConfigNoDefaults, err := c.oauth.Get(ctx, "cluster", metav1.GetOptions{})
if errors.IsNotFound(err) {
oauthConfigNoDefaults, err = c.oauth.Create(ctx, &configv1.OAuth{
ObjectMeta: defaultGlobalConfigMeta(),
}, metav1.CreateOptions{})
}
if err != nil {
return nil, err
}
oauthConfig := defaultOAuthConfig(oauthConfigNoDefaults)

var accessTokenInactivityTimeoutSeconds *int32
timeout := oauthConfig.Spec.TokenConfig.AccessTokenInactivityTimeoutSeconds
switch {
case timeout < 0:
zero := int32(0)
accessTokenInactivityTimeoutSeconds = &zero
case timeout == 0:
accessTokenInactivityTimeoutSeconds = nil
case timeout > 0:
accessTokenInactivityTimeoutSeconds = &timeout
}

// FIXME: add this to the observer
// handleDegraded(operatorConfig, "IdentityProviderConfig", v1helpers.NewMultiLineAggregate(errsIDP))

Expand Down Expand Up @@ -108,11 +83,6 @@ func (c *authOperator) handleOAuthConfig(
SessionMaxAgeSeconds: 5 * 60, // 5 minutes
SessionName: "ssn",
},
TokenConfig: osinv1.TokenConfig{
AuthorizeTokenMaxAgeSeconds: 5 * 60, // 5 minutes
AccessTokenMaxAgeSeconds: oauthConfig.Spec.TokenConfig.AccessTokenMaxAgeSeconds,
AccessTokenInactivityTimeoutSeconds: accessTokenInactivityTimeoutSeconds,
},
},
}

Expand Down Expand Up @@ -167,16 +137,6 @@ func getMasterCA() *string {
return &ca
}

func defaultOAuthConfig(oauthConfig *configv1.OAuth) *configv1.OAuth {
out := oauthConfig.DeepCopy() // do not mutate informer cache

if out.Spec.TokenConfig.AccessTokenMaxAgeSeconds == 0 {
out.Spec.TokenConfig.AccessTokenMaxAgeSeconds = 24 * 60 * 60 // 1 day
}

return out
}

func encodeOrDie(obj runtime.Object) []byte {
bytes, err := runtime.Encode(encoder, obj)
if err != nil {
Expand Down

0 comments on commit 08abc5f

Please sign in to comment.