-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LH-69472: Require that the API token provided is for a user with ADMI…
…N or SUPER_ADMIN privileges (#17) * verify only ADMIN and SUPER_ADMIN can perform actions * add tests
- Loading branch information
Showing
9 changed files
with
165 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
terraform { | ||
required_providers { | ||
cdo = { | ||
source = "hashicorp.com/CiscoDevnet/cdo" | ||
} | ||
} | ||
} | ||
|
||
provider "cdo" { | ||
base_url = "<https://www.defenseorchestrator.com|https://www.defenseorchestrator.eu|https://apj.cdo.cisco.com>" | ||
api_token = "<replace-with-api-token-generated-from-cdo>" | ||
} | ||
|
||
resource "cdo_ios_device" "my_ios" { | ||
name = "<name-of-device>" | ||
connector_name = "<name-of-sdc-connector>" | ||
socket_address = "<host>:<port>" | ||
username = "<username>" | ||
password = "<password>" | ||
ignore_certificate = true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package validators | ||
|
||
import ( | ||
"context" | ||
"encoding/base64" | ||
"encoding/json" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/golang-jwt/jwt/v5" | ||
"github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag" | ||
"github.com/hashicorp/terraform-plugin-framework/schema/validator" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
) | ||
|
||
const ( | ||
ErrInvalidTokenFormat = "invalid JWT token format" | ||
ErrDecodeFailed = "failed to decode token payload" | ||
ErrNoRolesFound = "no roles found in the JWT token" | ||
) | ||
|
||
var _ validator.String = oneOfRolesValidator{} | ||
|
||
// oneOfRolesValidator validates that the value matches one of expected roles. | ||
type oneOfRolesValidator struct { | ||
expectedRoles []types.String | ||
} | ||
|
||
func (v oneOfRolesValidator) Description(ctx context.Context) string { | ||
return v.MarkdownDescription(ctx) | ||
} | ||
|
||
func (v oneOfRolesValidator) MarkdownDescription(_ context.Context) string { | ||
return fmt.Sprintf("The user must be assigned one of the following CDO roles: %q", v.expectedRoles) | ||
} | ||
|
||
func (v oneOfRolesValidator) ValidateString(ctx context.Context, request validator.StringRequest, response *validator.StringResponse) { | ||
if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() { | ||
return | ||
} | ||
|
||
token := request.ConfigValue.String() | ||
|
||
role, err := extractRoleFromToken(token) | ||
|
||
if err != nil { | ||
fmt.Println("Error:", err) | ||
} | ||
|
||
for _, expectedRole := range v.expectedRoles { | ||
if role == expectedRole.ValueString() { | ||
return | ||
} | ||
} | ||
|
||
response.Diagnostics.Append(validatordiag.InvalidAttributeValueMatchDiagnostic( | ||
request.Path, | ||
v.Description(ctx), | ||
role, | ||
)) | ||
} | ||
|
||
func extractRoleFromToken(tokenString string) (string, error) { | ||
if tokenString == "" { | ||
return "", fmt.Errorf("tokenString is nil or empty") | ||
} | ||
|
||
parts := strings.Split(tokenString, ".") | ||
if len(parts) != 3 { | ||
return "", fmt.Errorf(ErrInvalidTokenFormat) | ||
} | ||
|
||
payloadBytes, err := base64.RawURLEncoding.DecodeString(parts[1]) | ||
if err != nil { | ||
return "", fmt.Errorf(ErrDecodeFailed) | ||
} | ||
|
||
var claims jwt.MapClaims | ||
if err := json.Unmarshal(payloadBytes, &claims); err != nil { | ||
return "", fmt.Errorf("failed to decode token payload: %v", err) | ||
} | ||
|
||
if rolesClaim, exists := claims["roles"]; exists { // check if "roles" claim exists | ||
if roles, ok := rolesClaim.([]interface{}); ok { // convert to a slice of interfaces | ||
if len(roles) > 0 { | ||
if role, ok := roles[0].(string); ok { | ||
return role, nil | ||
} | ||
} | ||
} | ||
} | ||
|
||
return "", fmt.Errorf(ErrNoRolesFound) | ||
} | ||
|
||
// OneOfRoles checks that the JWT token roles String held in the attribute | ||
// is one of the given `roles`. | ||
func OneOfRoles(roles ...string) validator.String { | ||
frameworkValues := make([]types.String, 0, len(roles)) | ||
|
||
for _, value := range roles { | ||
frameworkValues = append(frameworkValues, types.StringValue(value)) | ||
} | ||
|
||
return oneOfRolesValidator{ | ||
expectedRoles: frameworkValues, | ||
} | ||
} |
64 changes: 24 additions & 40 deletions
64
provider/validators/one_of_test.go → provider/validators/cdo_role_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.