@@ -18,15 +18,12 @@ package controllers
1818
1919import (
2020 "context"
21- "crypto/sha256"
22- "encoding/hex"
2321 "encoding/json"
2422 "fmt"
25- "strconv"
26- "time"
2723
2824 capabilitiesv1beta1 "github.com/3scale/3scale-operator/apis/capabilities/v1beta1"
2925 controllerhelper "github.com/3scale/3scale-operator/pkg/controller/helper"
26+ rand "github.com/3scale/3scale-operator/pkg/crypto/rand"
3027 "github.com/3scale/3scale-operator/pkg/helper"
3128 "github.com/3scale/3scale-operator/pkg/reconcilers"
3229 "github.com/3scale/3scale-operator/version"
@@ -133,6 +130,12 @@ func (r *ApplicationAuthReconciler) Reconcile(ctx context.Context, req ctrl.Requ
133130 return ctrl.Result {}, err
134131 }
135132
133+ authMode := product .Spec .AuthenticationMode ()
134+ if authMode == nil {
135+ err := fmt .Errorf ("unable to identify authentication mode from Product CR" )
136+ return reconcileStatus (r .BaseReconciler , applicationAuth , err , reqLogger )
137+ }
138+
136139 // Retrieve providerAccountRef
137140 providerAccount , err := controllerhelper .LookupProviderAccount (r .Client (), applicationAuth .GetNamespace (), applicationAuth .Spec .ProviderAccountRef , r .Logger ())
138141 if err != nil {
@@ -158,9 +161,14 @@ func (r *ApplicationAuthReconciler) Reconcile(ctx context.Context, req ctrl.Requ
158161 return ctrl.Result {}, err
159162 }
160163
161- // populate authSecret struct
162- authSecret := authSecretReferenceSource (r .Client (), applicationAuth .Namespace , applicationAuth .Spec .AuthSecretRef , reqLogger )
163- err = r .applicationAuthReconciler (applicationAuth , * developerAccount .Status .ID , * application .Status .ID , product , * authSecret , threescaleAPIClient )
164+ // populate authSecret struct and make sure required fields are available
165+ shouldGenerateSecret := applicationAuth .Spec .GenerateSecret != nil && * applicationAuth .Spec .GenerateSecret
166+ authSecret , err := authSecretReferenceSource (r .Client (), applicationAuth .Namespace , applicationAuth .Spec .AuthSecretRef , shouldGenerateSecret , * authMode , reqLogger )
167+ if err != nil {
168+ return reconcileStatus (r .BaseReconciler , applicationAuth , err , reqLogger )
169+ }
170+
171+ err = syncApplicationAuth (* developerAccount .Status .ID , * application .Status .ID , * authMode , * authSecret , threescaleAPIClient )
164172 if err != nil {
165173 return reconcileStatus (r .BaseReconciler , applicationAuth , err , reqLogger )
166174 }
@@ -176,109 +184,112 @@ func (r *ApplicationAuthReconciler) SetupWithManager(mgr ctrl.Manager) error {
176184 Complete (r )
177185}
178186
179- func (r * ApplicationAuthReconciler ) applicationAuthReconciler (
180- applicationAuth * capabilitiesv1beta1.ApplicationAuth ,
187+ func syncApplicationAuth (
181188 developerAccountID int64 ,
182189 applicationID int64 ,
183- product * capabilitiesv1beta1. Product ,
190+ authMode string ,
184191 authSecret AuthSecret ,
185192 threescaleClient * threescaleapi.ThreeScaleClient ,
186193) error {
187- // generate sha base of timestamp
188- timestamp := time .Now ().Unix ()
189- // Write the timestamp string and encode to hash
190- hash := sha256 .New ()
191- hash .Write ([]byte (strconv .FormatInt (timestamp , 10 )))
192- hashedBytes := hash .Sum (nil )
193- hashedString := hex .EncodeToString (hashedBytes )
194-
195- // Check the values if populated or the GenerateSecret field is true and make the api call to update
196- // If UserKey is not populated generate random sha
197- if authSecret .UserKey == "" && * applicationAuth .Spec .GenerateSecret {
198- authSecret .UserKey = hashedString
199- }
200- if authSecret .UserKey != "" {
201- params := make (map [string ]string )
202- params ["user_key" ] = authSecret .UserKey
203- // edge case if the operator is stopped before reconcile finished need to nil check application.Status.ID
204- _ , err := threescaleClient .UpdateApplication (developerAccountID , applicationID , params )
194+ switch authMode {
195+ case "1" :
196+ // get the existing value from the porta
197+ existingApplication , err := threescaleClient .Application (developerAccountID , applicationID )
205198 if err != nil {
206199 return err
207200 }
208- }
209-
210- if authSecret .ApplicationKey != "" {
211- foundApplication , err := threescaleClient .CreateApplicationKey (developerAccountID , applicationID , authSecret .ApplicationKey )
201+ existingKey := existingApplication .UserKey
202+
203+ // user_key mismatch, update
204+ if existingKey != authSecret .UserKey {
205+ params := make (map [string ]string )
206+ params ["user_key" ] = authSecret .UserKey
207+ if _ , err := threescaleClient .UpdateApplication (developerAccountID , applicationID , params ); err != nil {
208+ return err
209+ }
210+ }
211+ case "2" :
212+ // get the existing value from the portal
213+ existingKeys , err := threescaleClient .ApplicationKeys (developerAccountID , applicationID )
212214 if err != nil {
213215 return err
214216 }
215217
216- authSecret .ApplicationID = foundApplication .ApplicationId
217- }
218+ // pre-existing keys
219+ if len (existingKeys ) > 0 {
220+ // Nothing to do, return early
221+ if existingKeys [0 ].Value == authSecret .ApplicationKey {
222+ return nil
223+ }
218224
219- if applicationAuth . Spec . GenerateSecret != nil && * applicationAuth . Spec . GenerateSecret {
220- foundApplication , err := threescaleClient .CreateApplicationRandomKey (developerAccountID , applicationID )
221- if err != nil {
222- return err
225+ // if the key is not match, delete it
226+ if err := threescaleClient .DeleteApplicationKey (developerAccountID , applicationID , existingKeys [ 0 ]. Value ); err != nil {
227+ return err
228+ }
223229 }
224- authSecret .ApplicationID = foundApplication .ApplicationId
225- var foundApplicationKeys []threescaleapi.ApplicationKey
226- foundApplicationKeys , err = threescaleClient .ApplicationKeys (developerAccountID , applicationID )
227- if err != nil {
230+
231+ if _ , err := threescaleClient .CreateApplicationKey (developerAccountID , applicationID , authSecret .ApplicationKey ); err != nil {
228232 return err
229233 }
230- lastKey := len (foundApplicationKeys ) - 1
231- authSecret .ApplicationKey = fmt .Sprint (foundApplicationKeys [lastKey ].Value )
232- }
233-
234- // get the current values and update the secret
235- ApplicationAuthSecret := & corev1.Secret {}
236- err := r .Client ().Get (r .Context (), types.NamespacedName {
237- Name : applicationAuth .Spec .AuthSecretRef .Name ,
238- Namespace : applicationAuth .Namespace ,
239- }, ApplicationAuthSecret )
240- if err != nil {
241- // Handle errors gracefully, e.g., log and return or retry
242- r .Logger ().Error (err , "Failed to get existing ApplicationAuthSecret" )
243- return err
244- }
245- newData := ApplicationAuthSecret .Data
246- newValues := map [string ][]byte {
247- UserKey : []byte (authSecret .UserKey ),
248- ApplicationID : []byte (authSecret .ApplicationID ),
249- ApplicationKey : []byte (authSecret .ApplicationKey ),
250- }
251- for key , value := range newValues {
252- newData [key ] = value
253- }
254-
255- ApplicationAuthSecret .Data = newData
256- err = r .Client ().Update (r .Context (), ApplicationAuthSecret )
257- if err != nil {
258- r .Logger ().Error (err , "Failed to update ApplicationAuthSecret" )
259- return err
260234 }
261235
262236 return nil
263237}
264238
265- func authSecretReferenceSource (cl client.Client , ns string , authSectretRef * corev1.LocalObjectReference , logger logr.Logger ) * AuthSecret {
266- if authSectretRef != nil {
267- logger .Info ("LookupAuthSecret" , "ns" , ns , "authSecretRef" , authSectretRef )
268- secretSource := helper .NewSecretSource (cl , ns )
239+ func authSecretReferenceSource (cl client.Client , ns string , authSectretRef * corev1.LocalObjectReference , generateSecret bool , authMode string , logger logr.Logger ) (* AuthSecret , error ) {
240+ logger .Info ("LookupAuthSecret" , "ns" , ns , "authSecretRef" , authSectretRef )
241+ secretSource := helper .NewSecretSource (cl , ns )
242+
243+ switch authMode {
244+ case "1" :
269245 userKeyStr , err := secretSource .RequiredFieldValueFromRequiredSecret (authSectretRef .Name , UserKey )
270246 if err != nil {
271- userKeyStr = ""
247+ return nil , err
248+ }
249+
250+ if userKeyStr == "" {
251+ if generateSecret {
252+ userKeyStr = rand .String (16 )
253+
254+ newValues := map [string ][]byte {
255+ UserKey : []byte (userKeyStr ),
256+ }
257+
258+ if err := updateSecret (context .Background (), cl , authSectretRef .Name , ns , newValues ); err != nil {
259+ return nil , err
260+ }
261+ } else {
262+ // Nothing available raise error now
263+ return nil , fmt .Errorf ("no user_key available in secret and generate secret is set to false" )
264+ }
272265 }
266+ return & AuthSecret {UserKey : userKeyStr }, nil
267+ case "2" :
273268 applicationKeyStr , err := secretSource .RequiredFieldValueFromRequiredSecret (authSectretRef .Name , ApplicationKey )
274269 if err != nil {
275- applicationKeyStr = ""
270+ return nil , err
276271 }
277272
278- return & AuthSecret {UserKey : userKeyStr , ApplicationKey : applicationKeyStr }
279- }
273+ if applicationKeyStr == "" {
274+ if generateSecret {
275+ applicationKeyStr = rand .String (16 )
280276
281- return nil
277+ newValues := map [string ][]byte {
278+ ApplicationKey : []byte (applicationKeyStr ),
279+ }
280+
281+ if err := updateSecret (context .Background (), cl , authSectretRef .Name , ns , newValues ); err != nil {
282+ return nil , err
283+ }
284+ } else {
285+ // Nothing available raise error now
286+ return nil , fmt .Errorf ("no user_key available in secret and generate secret is set to false" )
287+ }
288+ }
289+ return & AuthSecret {ApplicationKey : applicationKeyStr }, nil
290+ default :
291+ return nil , fmt .Errorf ("unknown authentication mode" )
292+ }
282293}
283294
284295func reconcileStatus (b * reconcilers.BaseReconciler , resource * capabilitiesv1beta1.ApplicationAuth , err error , logger logr.Logger ) (ctrl.Result , error ) {
@@ -315,3 +326,30 @@ func checkApplicationResources(applicationAuthResource *capabilitiesv1beta1.Appl
315326
316327 return nil
317328}
329+
330+ func updateSecret (ctx context.Context , client client.Client , name string , namespace string , values map [string ][]byte ) error {
331+ // get the current values and update the secret
332+ secret := & corev1.Secret {}
333+ err := client .Get (ctx , types.NamespacedName {
334+ Name : name ,
335+ Namespace : namespace ,
336+ }, secret )
337+ if err != nil {
338+ // Handle errors gracefully, e.g., log and return or retry
339+ return err
340+ }
341+
342+ newData := secret .Data
343+
344+ for key , value := range values {
345+ newData [key ] = value
346+ }
347+
348+ secret .Data = newData
349+
350+ if err = client .Update (ctx , secret ); err != nil {
351+ return err
352+ }
353+
354+ return nil
355+ }
0 commit comments