Skip to content
This repository has been archived by the owner on Sep 9, 2024. It is now read-only.

Commit

Permalink
support external oauth credenital rotation
Browse files Browse the repository at this point in the history
  • Loading branch information
rathnapandi committed Apr 14, 2023
1 parent 5190ea6 commit d4701a7
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 37 deletions.
6 changes: 3 additions & 3 deletions pkg/cmd/discovery/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ func initConfig(centralConfig corecfg.CentralConfig) (interface{}, error) {
SetName(subscription.ApplicationTypeField).SetRequired().SetLabel("Application Type").
IsString().SetEnumValues([]string{"Confidential", "Public"}).SetFirstEnumValue("Confidential")

audience := provisioning.NewSchemaPropertyBuilder().
SetName(subscription.AudienceField).SetLabel("Audience").IsString().SetAsTextArea()
// audience := provisioning.NewSchemaPropertyBuilder().
// SetName(subscription.AudienceField).SetLabel("Audience").IsString().SetAsTextArea()

agent.NewAccessRequestBuilder().SetName(subscription.OAuth2AuthType).Register()

Expand All @@ -111,7 +111,7 @@ func initConfig(centralConfig corecfg.CentralConfig) (interface{}, error) {
coreagent.WithCRDOAuthSecret(),
coreagent.WithCRDRequestSchemaProperty(oAuthServers),
coreagent.WithCRDRequestSchemaProperty(oAuthType),
coreagent.WithCRDRequestSchemaProperty(audience),
// coreagent.WithCRDRequestSchemaProperty(audience),
coreagent.WithCRDRequestSchemaProperty(oAuthRedirects),
coreagent.WithCRDRequestSchemaProperty(corsProp)).SetName(subscription.OAuth2AuthType).IsRenewable().Register()

Expand Down
122 changes: 88 additions & 34 deletions pkg/subscription/provision.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ func (p provisioner) AccessRequestDeprovision(req prov.AccessRequest) prov.Reque
}

// process access request delete
// webmethodsApplicationId := req.GetApplicationDetailsValue(common.AttrAppID)
// if webmethodsApplicationId == "" {
// return p.failed(rs, notFound(common.AttrAppID))
// }
webmethodsApplicationId := req.GetApplicationDetailsValue(common.AttrAppID)
if webmethodsApplicationId == "" {
return p.failed(rs, notFound(common.AttrAppID))
}

// err := p.client.UnsubscribeApplication(webmethodsApplicationId, apiID)
// if err != nil {
// return p.failed(rs, notFound("Error removing API from Webmethods Application"))
// }
err := p.client.UnsubscribeApplication(webmethodsApplicationId, apiID)
if err != nil {
return p.failed(rs, notFound("Error removing API from Webmethods Application"))
}

p.log.
WithField("api", apiID).
Expand Down Expand Up @@ -118,7 +118,15 @@ func (p provisioner) ApplicationRequestDeprovision(req prov.ApplicationRequest)
if webmethodsApplicationId == "" {
return p.failed(rs, notFound(common.AttrAppID))
}
err := p.client.DeleteApplication(webmethodsApplicationId)
applicationResponse, err := p.client.GetApplication(webmethodsApplicationId)
if err != nil {
return p.failed(rs, notFound("Error calling webmethods"))
}
if len(applicationResponse.Applications) == 0 {
log.Warnf("Application with id %s is already deleted", webmethodsApplicationId)
return rs.Success()
}
err = p.client.DeleteApplication(webmethodsApplicationId)
if err != nil {
return p.failed(rs, notFound("Error Deleting Webmethods application"))
}
Expand All @@ -140,16 +148,28 @@ func (p provisioner) ApplicationRequestProvision(req prov.ApplicationRequest) pr
return p.failed(rs, notFound("managed application name"))
}

// process application create
var application webmethods.Application
application.Name = appName
application.Version = "1.0"
application.Description = "Amplify " + appName
createdApplication, err := p.client.CreateApplication(&application)
searchAppResponse, err := p.client.FindApplicationByName(appName)
if err != nil {
return p.failed(rs, notFound("Error creating application"))
return p.failed(rs, notFound("Error contacting webmethods"))
}
var applicationId string
if len(searchAppResponse.SearchApplication) == 0 {
log.Infof("Creating new application with name %s", appName)
var application webmethods.Application
application.Name = appName
application.Version = "1.0"
application.Description = "Amplify " + appName
createdApplication, err := p.client.CreateApplication(&application)
if err != nil {
return p.failed(rs, notFound("Error creating application"))
}
applicationId = createdApplication.ApplicationID
} else {
log.Infof("Using the exsting application with Id %s", searchAppResponse.SearchApplication[0].ApplicationID)
applicationId = searchAppResponse.SearchApplication[0].ApplicationID
}
rs.AddProperty(common.AttrAppID, createdApplication.Id)
// process application create
rs.AddProperty(common.AttrAppID, applicationId)
p.log.
WithField("appName", req.GetManagedApplicationName()).
Info("created application")
Expand Down Expand Up @@ -179,8 +199,20 @@ func (p provisioner) CredentialDeprovision(req prov.CredentialRequest) prov.Requ
}
case OAuth2AuthType:
log.Info("Removing oauth credential")
applicationsResponse, err := p.client.GetApplication(webmethodsApplicationId)
if err != nil {
return p.failed(rs, notFound("Unable to get application from Webmethods"))
}
if len(applicationsResponse.Applications[0].AuthStrategyIds) == 0 {
log.Warnf("Oauth Credential already cleaned up for application %s", applicationsResponse.Applications[0].Name)
return rs.Success()
}
strategyId := applicationsResponse.Applications[0].AuthStrategyIds[0]
err = p.client.DeleteStrategy(strategyId)
if err != nil {
return p.failed(rs, notFound("Unable to delete Oauth2 strategy from Webmethods"))
}
}

return rs.Success()
}

Expand Down Expand Up @@ -210,7 +242,19 @@ func (p provisioner) CredentialProvision(req prov.CredentialRequest) (prov.Reque

switch req.GetCredentialType() {
case prov.APIKeyCRD:
credential = prov.NewCredentialBuilder().SetAPIKey(applicationsResponse.Applications[0].AccessTokens.ApiAccessKeyCredentials.ApiAccessKey)
application := applicationsResponse.Applications[0]
if len(provData.cors) > 0 {
log.Infof("Update javascript origins for the application %s", application.Name)
// Updating java script origins
applicationsResponse.Applications[0].JsOrigins = append(application.JsOrigins, provData.cors...)
applicationUpdateResponse, err := p.client.UpdateApplication(&application)
if err != nil {
return p.failed(rs, notFound("Unable to to update Java Script Origins")), nil
}
credential = prov.NewCredentialBuilder().SetAPIKey(applicationUpdateResponse.AccessTokens.ApiAccessKeyCredentials.ApiAccessKey)
} else {
credential = prov.NewCredentialBuilder().SetAPIKey(application.AccessTokens.ApiAccessKeyCredentials.ApiAccessKey)
}
case OAuth2AuthType:
credential, err = createOrGetOauthCredential(applicationsResponse.Applications[0], provData, p)
if err != nil {
Expand All @@ -233,23 +277,27 @@ func (p provisioner) CredentialUpdate(req prov.CredentialRequest) (prov.RequestS
if webmethodsApplicationId == "" {
return p.failed(rs, notFound(common.AttrAppID)), nil
}
err := p.client.RotateApplicationApikey(webmethodsApplicationId)
if err != nil {
return p.failed(rs, notFound("Unable to Rotate Webmethods Application APIkey")), nil
}
applicationsResponse, err := p.client.GetApplication(webmethodsApplicationId)
if err != nil {
return p.failed(rs, notFound("Unable to get application from Webmethods")), nil
}

var credential prov.Credential

switch req.GetCredentialType() {
case prov.APIKeyCRD:
err := p.client.RotateApplicationApikey(webmethodsApplicationId)
if err != nil {
return p.failed(rs, notFound("Unable to Rotate Webmethods Application APIkey")), nil
}
applicationsResponse, err := p.client.GetApplication(webmethodsApplicationId)
if err != nil {
return p.failed(rs, notFound("Unable to get application from Webmethods")), nil
}
credential = prov.NewCredentialBuilder().SetAPIKey(applicationsResponse.Applications[0].AccessTokens.ApiAccessKeyCredentials.ApiAccessKey)
case OAuth2AuthType:
applicationsResponse, err := p.client.GetApplication(webmethodsApplicationId)
if err != nil {
return p.failed(rs, notFound("Unable to get application from Webmethods")), nil
}
strategyId := applicationsResponse.Applications[0].AuthStrategyIds[0]
log.Infof("Using existing Oauth Strategy named %s with id %s", applicationsResponse.Applications[0].Name, strategyId)
strategyResponse, err := p.client.GetStrategy(strategyId)
strategyResponse, err := p.client.RefereshOauth2Credential(strategyId)
if err != nil {
return p.failed(rs, notFound("Unable to get strategy from Webmethods")), nil
}
Expand All @@ -276,6 +324,7 @@ func getCredProvData(credData map[string]interface{}) credentialMetaData {
cors: []string{"*"},
redirectURLs: []string{},
appType: "Confidential",
audience: "",
}

// get cors from credential request
Expand All @@ -301,10 +350,10 @@ func getCredProvData(credData map[string]interface{}) credentialMetaData {
credMetaData.appType = data.(string)
}

// Audience type field
if data, ok := credData[AudienceField]; ok && data != nil {
credMetaData.audience = data.(string)
}
// // Audience type field
// if data, ok := credData[AudienceField]; ok && data != nil {
// credMetaData.audience = data.(string)
// }

return credMetaData
}
Expand Down Expand Up @@ -334,16 +383,21 @@ func createOrGetOauthCredential(application webmethods.Application, provData cre
ClientType: provData.appType,
ExpirationInterval: "3600",
RefreshCount: "100",
PkceType: "USE_GLOBAL_SETTING",
}
strategy := &webmethods.Strategy{
Name: application.Name,
Description: application.Name,
AuthServerAlias: provData.oauthServerName,
Audience: provData.audience,
Type: "OAUTH2",
Type: "OAUTH2_LOCAL_RSA",
DcrConfig: dcrconfig,
}

if provData.oauthServerName == "local" {
strategy.Type = "OAUTH2"
}

strategyResponse, err = p.client.CreateOauth2Strategy(strategy)
if err != nil {
return nil, errors.New("Unable to get application from Webmethods")
Expand Down
27 changes: 27 additions & 0 deletions pkg/webmethods/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type Client interface {
RotateApplicationApikey(applicationId string) error
CreateOauth2Strategy(strategy *Strategy) (*StrategyResponse, error)
DeleteStrategy(strategyId string) error
RefereshOauth2Credential(strategyId string) (*StrategyResponse, error)
GetStrategy(strategyId string) (*StrategyResponse, error)
DeleteApplication(applicationId string) error
OnConfigChange(webMethodConfig *config.WebMethodConfig) error
Expand Down Expand Up @@ -466,6 +467,32 @@ func (c *WebMethodClient) DeleteStrategy(strategyId string) error {
return nil
}

func (c *WebMethodClient) RefereshOauth2Credential(strategyId string) (*StrategyResponse, error) {
strategyResponse := &StrategyResponse{}

url := fmt.Sprintf("%s/rest/apigateway/strategies/%s/refreshCredentials", c.url, strategyId)
headers := map[string]string{
"Authorization": c.createAuthToken(),
"Content-Type": "application/json",
}
request := coreapi.Request{
Method: coreapi.PUT,
URL: url,
Headers: headers,
}

response, err := c.httpClient.Send(request)
if err != nil {
return nil, err
}

err = json.Unmarshal(response.Body, strategyResponse)
if err != nil {
return nil, err
}
return strategyResponse, nil
}

func (c *WebMethodClient) DeleteApplication(applicationId string) error {
url := fmt.Sprintf("%s/rest/apigateway/applications/%s", c.url, applicationId)
headers := map[string]string{
Expand Down
19 changes: 19 additions & 0 deletions pkg/webmethods/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5289,6 +5289,25 @@ func TestFindApplicationByName(t *testing.T) {

}

func TestFindApplicationByNameNegative(t *testing.T) {

response := `{
"application": []
}`
mc := &MockClient{}
webMethodsClient, _ := NewClient(cfg, mc)
mc.SendFunc = func(request coreapi.Request) (*coreapi.Response, error) {
return &coreapi.Response{
Code: 200,
Body: []byte(response),
}, nil
}
applicationResponse, err := webMethodsClient.FindApplicationByName("oauthokta")
assert.Nil(t, err)
assert.Equal(t, len(applicationResponse.SearchApplication), 0)

}

func TestCreateOauth2Strategy(t *testing.T) {
request := `{
"name": "oauthdynamic2",
Expand Down
1 change: 1 addition & 0 deletions pkg/webmethods/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ type DcrConfig struct {
ClientType string `json:"clientType"`
ExpirationInterval string `json:"expirationInterval"`
RefreshCount string `json:"refreshCount"`
PkceType string `json:"pkceType"`
}

type StrategyResponse struct {
Expand Down

0 comments on commit d4701a7

Please sign in to comment.