Skip to content

Commit

Permalink
Remove unecessary apiProduct operations (#15)
Browse files Browse the repository at this point in the history
* remove unecessary apiProduct operations

* remove api product util

* remove unused helper methods + update client creation e2e endpoint
  • Loading branch information
inFocus7 authored Oct 23, 2024
1 parent dc856d7 commit 5fdbdd7
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 2,006 deletions.
156 changes: 3 additions & 153 deletions api/v1/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ openapi: 3.0.0
servers:
- url: https://api.gloo-platform-portal.com/v1
paths:
/applications/oauth2:
/applications:
post:
description: Creates an application of type oauth2. This is intended to be integrated with an Open Id Connect Provider that the IDP Connect implementation integrates with. Note that the `clientSecret` is never stored in the database and is shown to the user only once. Keep this secret to make future requests to the API products in the Portal.
operationId: CreateOAuthApplication
Expand Down Expand Up @@ -47,8 +47,8 @@ paths:
- Applications
/applications/{id}:
delete:
description: Delete application.
operationId: DeleteApplication
description: Delete an oauth2 application.
operationId: DeleteOAuthApplication
parameters:
- in: path
name: "id"
Expand All @@ -74,158 +74,8 @@ paths:
summary: Deletes an application in the OpenID Connect Provider.
tags:
- Applications
/applications/{id}/api-products:
put:
description: Update application's API Products.
operationId: UpdateAppAPIProducts
parameters:
- in: path
name: "id"
required: true
description: (Required) Application ID to add API Product to.
schema:
type: string
requestBody:
description: Add API Product for a specific application.
required: true
content:
application/json:
schema:
type: object
required:
- apiProducts
properties:
apiProducts:
type: array
items:
type: string
example: "example-api-product"
responses:
'204':
description: Successfully added API Product to application.
'400':
description: Invalid input.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Application not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected error adding application API Products.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
summary: Updates the set of API Products that the application has access to in the OpenID Connect Provider.
tags:
- Applications
/api-products:
post:
description: Creates API Product in the Open Id Connect Provider.
operationId: CreateAPIProduct
requestBody:
description: Create API Product for associated with your applications.
required: true
content:
application/json:
schema:
type: object
required:
- apiProduct
properties:
apiProduct:
$ref: '#/components/schemas/ApiProduct'
responses:
'201':
description: Successfully created API Product.
'400':
description: Invalid input.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: API Product already exists.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected error creating API Product.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
summary: Creates API Product in the OpenID Connect Provider. Then, you can add this API Product to the application for your Portal applications with the `PUT /applications/{id}/api-products` API request.
tags:
- API Products
get:
description: Get all API Products in the Open Id Connect Provider. The Portal uses the results to keep the API Products in the IdP in sync with Portal by creating and deleting as needed.
operationId: GetAPIProducts
responses:
'200':
description: Successfully retrieved API Products.
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/ApiProduct'
'500':
description: Unexpected error retrieving API Products.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
summary: Get all API Products in the OpenID Connect Provider.
tags:
- API Products
/api-products/{name}:
delete:
description: Deletes API Product in the Open Id Connect Provider for a given unique identifier.
operationId: DeleteAPIProduct
parameters:
- in: path
name: "name"
required: true
description: (Required) Name of the API Product we'd like to delete.
schema:
type: string
responses:
'204':
description: Successfully deleted API Product.
'404':
description: API Product not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected error deleting API Product.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
summary: Deletes API Product in the OpenID Connect Provider.
tags:
- API Products
components:
schemas:
ApiProduct:
required:
- name
properties:
name:
type: string
example: "example-api-product"
description:
type: string
example: "example API Product description"
OAuthApplication:
required:
- clientId
Expand Down
181 changes: 7 additions & 174 deletions internal/cognito/server/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package server
import (
"context"
"errors"
"fmt"

"github.com/aws/aws-sdk-go-v2/aws"
cognito "github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider"
"github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider/types"
Expand Down Expand Up @@ -68,11 +66,11 @@ func NewStrictServerHandler(opts *Options, cognitoClient CognitoClient) *StrictS
}
}

// DeleteApplication deletes an application by ID.
func (s *StrictServerHandler) DeleteApplication(
// DeleteOAuthApplication deletes an application by ID.
func (s *StrictServerHandler) DeleteOAuthApplication(
ctx context.Context,
request portalv1.DeleteApplicationRequestObject,
) (portalv1.DeleteApplicationResponseObject, error) {
request portalv1.DeleteOAuthApplicationRequestObject,
) (portalv1.DeleteOAuthApplicationResponseObject, error) {
_, err := s.cognitoClient.DeleteUserPoolClient(ctx, &cognito.DeleteUserPoolClientInput{
UserPoolId: &s.userPool,
ClientId: aws.String(request.Id),
Expand All @@ -82,14 +80,14 @@ func (s *StrictServerHandler) DeleteApplication(
if err != nil {
switch cognitoErr := unwrapCognitoError(err); cognitoErr.Code {
case 404:
return portalv1.DeleteApplication404JSONResponse(cognitoErr), nil
return portalv1.DeleteOAuthApplication404JSONResponse(cognitoErr), nil
default:
return portalv1.DeleteApplication500JSONResponse(cognitoErr), nil
return portalv1.DeleteOAuthApplication500JSONResponse(cognitoErr), nil
}
}
}

return portalv1.DeleteApplication204Response{}, nil
return portalv1.DeleteOAuthApplication204Response{}, nil
}

// CreateOAuthApplication creates a client in Cognito
Expand Down Expand Up @@ -118,161 +116,6 @@ func (s *StrictServerHandler) CreateOAuthApplication(
}, nil
}

// UpdateAppAPIProducts updates scopes for a client in Cognito.
func (s *StrictServerHandler) UpdateAppAPIProducts(
ctx context.Context,
request portalv1.UpdateAppAPIProductsRequestObject,
) (portalv1.UpdateAppAPIProductsResponseObject, error) {
if request.Body == nil {
return portalv1.UpdateAppAPIProducts400JSONResponse(newPortal400Error("request body is required")), nil
}

var cognitoScopes []string
for _, apiProduct := range request.Body.ApiProducts {
cognitoScopes = append(cognitoScopes, fmt.Sprintf("%s/%s", s.resourceServer, apiProduct))
}

clientInput := &cognito.UpdateUserPoolClientInput{
UserPoolId: &s.userPool,
ClientId: &request.Id,
AllowedOAuthScopes: cognitoScopes,
}
if len(cognitoScopes) != 0 {
clientInput.AllowedOAuthFlowsUserPoolClient = true
clientInput.AllowedOAuthFlows = []types.OAuthFlowType{
types.OAuthFlowTypeClientCredentials,
}
}

_, err := s.cognitoClient.UpdateUserPoolClient(ctx, clientInput)

if err != nil {
switch cognitoErr := unwrapCognitoError(err); cognitoErr.Code {
case 404:
return portalv1.UpdateAppAPIProducts404JSONResponse(cognitoErr), nil
default:
return portalv1.UpdateAppAPIProducts500JSONResponse(cognitoErr), nil
}
}

return portalv1.UpdateAppAPIProducts204Response{}, nil
}

// DeleteAPIProduct deletes scopes in Cognito
func (s *StrictServerHandler) DeleteAPIProduct(
ctx context.Context,
request portalv1.DeleteAPIProductRequestObject,
) (portalv1.DeleteAPIProductResponseObject, error) {
out, err := s.cognitoClient.DescribeResourceServer(ctx, &cognito.DescribeResourceServerInput{
UserPoolId: &s.userPool,
Identifier: aws.String(s.resourceServer),
})
if err != nil {
switch cognitoErr := unwrapCognitoError(err); cognitoErr.Code {
case 404:
return portalv1.DeleteAPIProduct404JSONResponse(cognitoErr), nil
default:
return portalv1.DeleteAPIProduct500JSONResponse(cognitoErr), nil
}
}

scopeExists := false
var updatedScopes []types.ResourceServerScopeType
for _, scope := range out.ResourceServer.Scopes {
if scope.ScopeName == nil {
continue
}

if *scope.ScopeName == request.Name {
scopeExists = true
continue
}

updatedScopes = append(updatedScopes, scope)
}

if !scopeExists {
// Return early as if scope was deleted even if it doesn't exist, since resultant state is the same.
return portalv1.DeleteAPIProduct404JSONResponse{}, nil
}

_, err = s.cognitoClient.UpdateResourceServer(ctx, &cognito.UpdateResourceServerInput{
UserPoolId: &s.userPool,
Identifier: aws.String(s.resourceServer),
Name: aws.String(s.resourceServer),
Scopes: updatedScopes,
})
if err != nil {
return portalv1.DeleteAPIProduct500JSONResponse(unwrapCognitoError(err)), nil
}

return portalv1.DeleteAPIProduct204Response{}, nil
}

// CreateAPIProduct creates scopes in Cognito
func (s *StrictServerHandler) CreateAPIProduct(
ctx context.Context,
request portalv1.CreateAPIProductRequestObject,
) (portalv1.CreateAPIProductResponseObject, error) {
if request.Body == nil {
return portalv1.CreateAPIProduct400JSONResponse(newPortal400Error("request body is required")), nil
}

if request.Body.ApiProduct.Description == nil {
request.Body.ApiProduct.Description = aws.String(request.Body.ApiProduct.Name)
}

out, err := s.cognitoClient.DescribeResourceServer(ctx, &cognito.DescribeResourceServerInput{
UserPoolId: &s.userPool,
Identifier: aws.String(s.resourceServer),
})

if err != nil {
var notFoundErr *types.ResourceNotFoundException
if !errors.As(err, &notFoundErr) {
return portalv1.CreateAPIProduct500JSONResponse(unwrapCognitoError(err)), nil
}

// If Resource Server does not exist, create it.
if err = createResourceServer(ctx, s); err != nil {
return portalv1.CreateAPIProduct500JSONResponse(newPortal500Error(err.Error())), nil
}
}

var cognitoScopes []types.ResourceServerScopeType
if out != nil {
cognitoScopes = out.ResourceServer.Scopes
}

inScope := apiProductToCognitoScopeType(request.Body.ApiProduct)
for _, scope := range cognitoScopes {
if *scope.ScopeName == *inScope.ScopeName {
return portalv1.CreateAPIProduct409JSONResponse(newPortalError(409, "Resource Exists", "scope already exists")), nil
}
}

cognitoScopes = append(cognitoScopes, inScope)

_, err = s.cognitoClient.UpdateResourceServer(ctx, &cognito.UpdateResourceServerInput{
UserPoolId: &s.userPool,
Identifier: aws.String(s.resourceServer),
Name: aws.String(s.resourceServer),
Scopes: cognitoScopes,
})
if err != nil {
return portalv1.CreateAPIProduct500JSONResponse(unwrapCognitoError(err)), nil
}

return portalv1.CreateAPIProduct201Response{}, nil
}

func (s *StrictServerHandler) GetAPIProducts(
_ context.Context,
_ portalv1.GetAPIProductsRequestObject,
) (portalv1.GetAPIProductsResponseObject, error) {
panic("implement me")
}

func unwrapCognitoError(err error) portalv1.Error {
var notFoundErr *types.ResourceNotFoundException
if ok := errors.As(err, &notFoundErr); ok {
Expand All @@ -294,13 +137,3 @@ func unwrapCognitoError(err error) portalv1.Error {

return newPortal500Error(err.Error())
}

func createResourceServer(ctx context.Context, s *StrictServerHandler) error {
_, err := s.cognitoClient.CreateResourceServer(ctx, &cognito.CreateResourceServerInput{
UserPoolId: &s.userPool,
Identifier: aws.String(s.resourceServer),
Name: aws.String(s.resourceServer),
})

return err
}
Loading

0 comments on commit 5fdbdd7

Please sign in to comment.