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

Commit

Permalink
support oauth2 auth
Browse files Browse the repository at this point in the history
  • Loading branch information
rathnapandi committed Apr 14, 2023
1 parent 93aefcd commit 93af0c1
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 47 deletions.
22 changes: 17 additions & 5 deletions pkg/cmd/discovery/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/Axway/agent-sdk/pkg/apic/provisioning"
"github.com/sirupsen/logrus"

"git.ecd.axway.org/apigov/agents-webmethods/pkg/subscription"
subs "git.ecd.axway.org/apigov/agents-webmethods/pkg/subscription"
"git.ecd.axway.org/apigov/agents-webmethods/pkg/webmethods"
coreagent "github.com/Axway/agent-sdk/pkg/agent"
Expand Down Expand Up @@ -88,22 +89,33 @@ func initConfig(centralConfig corecfg.CentralConfig) (interface{}, error) {

agent.RegisterProvisioner(subs.NewProvisioner(gatewayClient, logger))
agent.NewAPIKeyAccessRequestBuilder().Register()

agent.NewAPIKeyCredentialRequestBuilder(coreagent.WithCRDRequestSchemaProperty(corsProp)).IsRenewable().Register()
oAuthRedirects := getAuthRedirectSchemaPropertyBuilder()

oAuthServers := provisioning.NewSchemaPropertyBuilder().
SetName("oauthServer").
SetName(subscription.OauthServerField).
SetRequired().
SetLabel("Oauth Server").
IsString().
SetEnumValues(servers)

oAuthType := provisioning.NewSchemaPropertyBuilder().
SetName(subscription.ApplicationTypeField).
SetRequired().
SetLabel("Application Type").
IsString().
SetEnumValues([]string{"Confidential", "Public"})

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

agent.NewOAuthCredentialRequestBuilder(
//coreagent.WithCRDSco
coreagent.WithCRDOAuthSecret(),
coreagent.WithCRDRequestSchemaProperty(oAuthRedirects),
coreagent.WithCRDRequestSchemaProperty(oAuthServers),
coreagent.WithCRDRequestSchemaProperty(corsProp)).IsRenewable().Register()
coreagent.WithCRDRequestSchemaProperty(oAuthType),
coreagent.WithCRDRequestSchemaProperty(oAuthRedirects),
coreagent.WithCRDRequestSchemaProperty(corsProp)).SetName(subscription.OAuth2AuthType).IsRenewable().Register()

discoveryAgent = discovery.NewAgent(conf, gatewayClient)
return conf, nil
Expand All @@ -112,7 +124,7 @@ func initConfig(centralConfig corecfg.CentralConfig) (interface{}, error) {
func getCorsSchemaPropertyBuilder() provisioning.PropertyBuilder {
// register the supported credential request defs
return provisioning.NewSchemaPropertyBuilder().
SetName("cors").
SetName(subscription.CorsField).
SetLabel("Javascript Origins").
IsArray().
AddItem(
Expand All @@ -123,7 +135,7 @@ func getCorsSchemaPropertyBuilder() provisioning.PropertyBuilder {

func getAuthRedirectSchemaPropertyBuilder() provisioning.PropertyBuilder {
return provisioning.NewSchemaPropertyBuilder().
SetName("redirectURLs").
SetName(subscription.RedirectURLsField).
SetLabel("Redirect URLs").
IsArray().
AddItem(
Expand Down
5 changes: 3 additions & 2 deletions pkg/discovery/servicehandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,9 @@ func (s *serviceHandler) getServiceDetail(api *webmethods.AmplifyAPI) (*ServiceD
break
}
if value == apic.Oauth {
ardName = provisioning.OauthTokenAuthMethod
crds[0] = provisioning.OAuthIDPCRD
ardName = "oauth2"
crds[0] = "oauth2"
break
}
}
}
Expand Down
180 changes: 140 additions & 40 deletions pkg/subscription/provision.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package subscription

import (
"errors"
"fmt"

"git.ecd.axway.org/apigov/agents-webmethods/pkg/common"
Expand All @@ -11,6 +12,20 @@ import (
"github.com/sirupsen/logrus"
)

const (
// CorsField -
CorsField = "cors"
// RedirectURLsField -
RedirectURLsField = "redirectURLs"
OauthServerField = "oauthServer"

OAuth2AuthType = "oauth2"

ApplicationTypeField = "applicationType"
// ClientTypeField -
ClientTypeField = "clientType"
)

type provisioner struct {
client webmethods.Client
log logrus.FieldLogger
Expand All @@ -36,15 +51,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 @@ -84,6 +99,7 @@ func (p provisioner) AccessRequestProvision(req prov.AccessRequest) (prov.Reques
return p.failed(rs, notFound("Error assocating API to Webmethods Application")), nil
}
// process access request create
rs.AddProperty(common.AttrAppID, webmethodsApplicationId)
p.log.
WithField("api", apiID).
WithField("app", req.GetApplicationName()).
Expand Down Expand Up @@ -145,17 +161,23 @@ func (p provisioner) CredentialDeprovision(req prov.CredentialRequest) prov.Requ
msg := "credentials will be removed when the subscription is deleted"
p.log.Info(msg)
rs := prov.NewRequestStatusBuilder()

log.Infof("Credential Type %s", req.GetCredentialType())
// process credential delete
webmethodsApplicationId := req.GetCredentialDetailsValue(common.AttrAppID)
log.Infof("webmethodsApplicationId : %s", webmethodsApplicationId)

if webmethodsApplicationId == "" {
return p.failed(rs, notFound(common.AttrAppID))
}
err := p.client.DeleteApplicationAccessTokens(webmethodsApplicationId)
if err != nil {
return p.failed(rs, notFound("Unable to clear application credentials from Webmethods"))

switch req.GetCredentialType() {
case prov.APIKeyCRD:
err := p.client.DeleteApplicationAccessTokens(webmethodsApplicationId)
if err != nil {
return p.failed(rs, notFound("Unable to clear application credentials from Webmethods"))
}
case OAuth2AuthType:
log.Info("Removing oauth credential")
}

return rs.Success()
Expand Down Expand Up @@ -183,39 +205,17 @@ func (p provisioner) CredentialProvision(req prov.CredentialRequest) (prov.Reque
return p.failed(rs, notFound("Unable to get application from Webmethods")), nil
}
var credential prov.Credential
provData := getCredProvData(req.GetCredentialData())

switch req.GetCredentialType() {
case prov.APIKeyCRD:
credential = prov.NewCredentialBuilder().SetAPIKey(applicationsResponse.Applications[0].AccessTokens.ApiAccessKeyCredentials.ApiAccessKey)
case prov.OAuthIDPCRD:
dcrconfig := webmethods.DcrConfig{}
strategy := &webmethods.Strategy{
Name: "test",
Description: "test",
AuthServerAlias: "",
Audience: "",
Type: "OAUTH2",
DcrConfig: dcrconfig,
}

strategyResponse, err := p.client.CreateOauth2Strategy(strategy)
if err != nil {
return p.failed(rs, notFound("Unable to get application from Webmethods")), nil

}

application := applicationsResponse.Applications[0]
application.AuthStrategyIds = []string{strategyResponse.Strategy.Id}
applicationsResponse, err := p.client.UpdateApplication(&application)
case OAuth2AuthType:
credential, err = createOrGetOauthCredential(applicationsResponse.Applications[0], provData, p)
if err != nil {
return p.failed(rs, notFound("Unable to get update Webmethods applicaiton")), nil
return p.failed(rs, notFound(err.Error())), nil
}
if applicationsResponse == nil {
return p.failed(rs, notFound("Unable to get update Webmethods applicaiton")), nil
}
credential = prov.NewCredentialBuilder().SetOAuthIDAndSecret(strategyResponse.Strategy.ClientRegistration.ClientId, strategyResponse.Strategy.ClientRegistration.ClientSecret)
}

rs.AddProperty(common.AttrAppID, webmethodsApplicationId)
p.log.Info("created credentials")
return rs.Success(), credential
Expand Down Expand Up @@ -245,14 +245,21 @@ func (p provisioner) CredentialUpdate(req prov.CredentialRequest) (prov.RequestS
switch req.GetCredentialType() {
case prov.APIKeyCRD:
credential = prov.NewCredentialBuilder().SetAPIKey(applicationsResponse.Applications[0].AccessTokens.ApiAccessKeyCredentials.ApiAccessKey)
case prov.OAuthIDPCRD:
credential = prov.NewCredentialBuilder().SetOAuthIDAndSecret("", "")
case OAuth2AuthType:
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)
if err != nil {
return p.failed(rs, notFound("Unable to get strategy from Webmethods")), nil
}
credential = prov.NewCredentialBuilder().SetOAuthIDAndSecret(strategyResponse.Strategy.ClientRegistration.ClientId, strategyResponse.Strategy.ClientRegistration.ClientSecret)
}
p.log.Infof("updated credentials for app %s", req.GetApplicationName())
return rs.Success(), credential
}

func (p provisioner) failed(rs prov.RequestStatusBuilder, err error) prov.RequestStatus {
log.Info("handle failed event")
rs.SetMessage(err.Error())
p.log.Error(err)
return rs.Failed()
Expand All @@ -261,3 +268,96 @@ func (p provisioner) failed(rs prov.RequestStatusBuilder, err error) prov.Reques
func notFound(msg string) error {
return fmt.Errorf("%s not found", msg)
}

func getCredProvData(credData map[string]interface{}) credentialMetaData {
// defaults
credMetaData := credentialMetaData{
cors: []string{"*"},
redirectURLs: []string{},
appType: "Confidential",
}

// get cors from credential request
if data, ok := credData[CorsField]; ok && data != nil {
credMetaData.cors = []string{}
for _, c := range data.([]interface{}) {
credMetaData.cors = append(credMetaData.cors, c.(string))
}
}
// get redirectURLs
if data, ok := credData[RedirectURLsField]; ok && data != nil {
credMetaData.redirectURLs = []string{}
for _, u := range data.([]interface{}) {
credMetaData.redirectURLs = append(credMetaData.redirectURLs, u.(string))
}
}
// Oauth Server field
if data, ok := credData[OauthServerField]; ok && data != nil {
credMetaData.oauthServerName = data.(string)
}
// credential type field
if data, ok := credData[ApplicationTypeField]; ok && data != nil {
credMetaData.appType = data.(string)
}

return credMetaData
}

type credentialMetaData struct {
cors []string
redirectURLs []string
oauthServerName string
appType string
}

func createOrGetOauthCredential(application webmethods.Application, provData credentialMetaData, p provisioner) (prov.Credential, error) {
var strategyResponse *webmethods.StrategyResponse
var err error
if len(application.AuthStrategyIds) == 0 {
log.Infof("Creating new Oauth Strategy named %s", application.Name)
dcrconfig := webmethods.DcrConfig{
AllowedGrantTypes: []string{"authorization_code",
"password",
"client_credentials",
"refresh_token",
"implicit"},
RedirectUris: provData.redirectURLs,
AuthServer: provData.oauthServerName,
ApplicationType: "web",
ClientType: provData.appType,
ExpirationInterval: "3600",
RefreshCount: "100",
}
strategy := &webmethods.Strategy{
Name: application.Name,
Description: application.Name,
AuthServerAlias: provData.oauthServerName,
Audience: "",
Type: "OAUTH2",
DcrConfig: dcrconfig,
}

strategyResponse, err = p.client.CreateOauth2Strategy(strategy)
if err != nil {
return nil, errors.New("Unable to get application from Webmethods")
}

application.AuthStrategyIds = []string{strategyResponse.Strategy.Id}
applicationsResponse, err := p.client.UpdateApplication(&application)
if err != nil {
return nil, errors.New("Unable to get update Webmethods applicaiton")
}
if applicationsResponse == nil {
return nil, errors.New("Unable to get update Webmethods applicaiton")
}
} else {
strategyId := application.AuthStrategyIds[0]
log.Infof("Using existing Oauth Strategy named %s with id %s", application.Name, strategyId)
strategyResponse, err = p.client.GetStrategy(strategyId)
if err != nil {
return nil, errors.New("Unable to get strategy from Webmethods")
}
}
credential := prov.NewCredentialBuilder().SetOAuthIDAndSecret(strategyResponse.Strategy.ClientRegistration.ClientId, strategyResponse.Strategy.ClientRegistration.ClientSecret)
return credential, nil
}
23 changes: 23 additions & 0 deletions pkg/webmethods/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type Client interface {
GetApplication(applicationId string) (*ApplicationResponse, error)
RotateApplicationApikey(applicationId string) error
CreateOauth2Strategy(strategy *Strategy) (*StrategyResponse, error)
DeleteStrategy(strategyId string) error
GetStrategy(strategyId string) (*StrategyResponse, error)
DeleteApplication(applicationId string) error
OnConfigChange(webMethodConfig *config.WebMethodConfig) error
Expand Down Expand Up @@ -443,6 +444,28 @@ func (c *WebMethodClient) RotateApplicationApikey(applicationId string) error {
return nil
}

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

response, err := c.httpClient.Send(request)
if err != nil {
return err
}
if response.Code != 204 {
return agenterrors.Newf(2001, "Unable to Delete Stratgey")
}
return 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

0 comments on commit 93af0c1

Please sign in to comment.