Skip to content

Commit

Permalink
Feat: Add support to Contacts for CertReq on TPP
Browse files Browse the repository at this point in the history
- The tpp.Connector.resolveContacts() method was refactored so it can be user
not only for SetPolicy purpose but also for Request Certificate.
- The Structs related to Identity were moved from policy package to tpp package.
- The tpp.prepareRequest() function was converted in a tpp.Connector method and
it also was to it the management to resolve and set the Contacts to the
TPP Certificate Request.
  • Loading branch information
marcos-albornoz committed Jan 24, 2024
1 parent d5b37ae commit cc13171
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 62 deletions.
15 changes: 15 additions & 0 deletions pkg/certificate/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@ type Request struct {
ValidityPeriod string //represents the validity of the certificate expressed as an ISO 8601 duration
IssuerHint util.IssuerHint

// ContactEmails is TPP-specific. It allows you to configure an email
// address to send notifications about the certificate to. When an email is
// used by multiple TPP identities, the first identity found is picked
// arbitrarily.
//
// The scope `configuration` is required. Since ContactEmails works by
// searching the emails in the same LDAP or AD as the user attached to the
// token, you must check that you are using a user in that same identity
// provider. ContactEmails doesn't work with the local TPP identities. Using
// ContactEmails requires adding `mail` to the list of fields searched when
// performing a user search, which can be configured in the Venafi
// Configuration Console by RDP'ing into the TPP VM. This configuration
// cannot be performed directly in the TPP UI.
Contacts []string

// Deprecated: use ValidityDuration instead, this field is ignored if ValidityDuration is set
ValidityHours int
}
Expand Down
36 changes: 0 additions & 36 deletions pkg/policy/policyStructures.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,42 +155,6 @@ type TppPolicy struct {
WantRenewal *int
}

type BrowseIdentitiesRequest struct {
Filter string
Limit int
IdentityType int
}

type BrowseIdentitiesResponse struct {
Identities []IdentityEntry
}

type IdentitySelfResponse struct {
Identities []IdentityEntry
}

type ValidateIdentityRequest struct {
ID IdentityInformation
}

type ValidateIdentityResponse struct {
ID IdentityEntry
}

type IdentityInformation struct {
PrefixedUniversal string
}

type IdentityEntry struct {
FullName string
Name string
Prefix string
PrefixedName string
PrefixedUniversal string
Type int
Universal string
}

type LockedAttribute struct {
Value string
Locked bool
Expand Down
59 changes: 43 additions & 16 deletions pkg/venafi/tpp/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ func (c *Connector) setCertificateMetadata(metadataRequest metadataSetRequest) (
return result.Locked, nil
}

func prepareRequest(req *certificate.Request, zone string) (tppReq certificateRequest, err error) {
func (c *Connector) prepareRequest(req *certificate.Request, zone string) (tppReq certificateRequest, err error) {
switch req.CsrOrigin {
case certificate.LocalGeneratedCSR, certificate.UserProvidedCSR:
tppReq.PKCS10 = string(req.GetCSR())
Expand Down Expand Up @@ -582,6 +582,20 @@ func prepareRequest(req *certificate.Request, zone string) (tppReq certificateRe
}
}

//resolving Contacts if them were provide
var contacts []IdentityEntry
if req.Contacts != nil {
var err error
prefixedUniversals, err := c.resolvePrefixedUniversals(req.Contacts)
if err != nil {
return tppReq, fmt.Errorf("failed to find contact identities: %w", err)
}
for _, prefixedUniversal := range prefixedUniversals {
contacts = append(contacts, IdentityEntry{PrefixedUniversal: prefixedUniversal})
}
}
tppReq.Contacts = contacts

for name, value := range customFieldsMap {
tppReq.CustomFields = append(tppReq.CustomFields, customField{name, value})
}
Expand Down Expand Up @@ -693,7 +707,7 @@ func (c *Connector) RequestCertificate(req *certificate.Request) (requestID stri
return
}
}
tppCertificateRequest, err := prepareRequest(req, c.zone)
tppCertificateRequest, err := c.prepareRequest(req, c.zone)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -890,8 +904,8 @@ func (c *Connector) retrieveUserNamesForPolicySpecification(policyName string) (
if values != nil {
var users []string
for _, prefixedUniversal := range values {
validateIdentityRequest := policy.ValidateIdentityRequest{
ID: policy.IdentityInformation{
validateIdentityRequest := ValidateIdentityRequest{
ID: IdentityInformation{
PrefixedUniversal: prefixedUniversal,
},
}
Expand All @@ -910,7 +924,7 @@ func (c *Connector) retrieveUserNamesForPolicySpecification(policyName string) (
return nil, nil
}

func (c *Connector) validateIdentity(validateIdentityRequest policy.ValidateIdentityRequest) (*policy.ValidateIdentityResponse, error) {
func (c *Connector) validateIdentity(validateIdentityRequest ValidateIdentityRequest) (*ValidateIdentityResponse, error) {

statusCode, status, body, err := c.request("POST", urlResourceValidateIdentity, validateIdentityRequest)
if err != nil {
Expand Down Expand Up @@ -1172,7 +1186,7 @@ func (c *Connector) SetPolicy(name string, ps *policy.PolicySpecification) (stri
func (c *Connector) setContact(tppPolicy *policy.TppPolicy) (status string, err error) {

if tppPolicy.Contact != nil {
contacts, err := c.resolveContacts(tppPolicy.Contact)
contacts, err := c.resolvePrefixedUniversals(tppPolicy.Contact)
if err != nil {
return "", fmt.Errorf("an error happened trying to resolve the contacts: %w", err)
}
Expand All @@ -1189,15 +1203,28 @@ func (c *Connector) setContact(tppPolicy *policy.TppPolicy) (status string, err
return status, nil
}

func (c *Connector) resolveContacts(contacts []string) ([]string, error) {
var identities []string
uniqueContacts := getUniqueStringSlice(contacts)
func (c *Connector) resolvePrefixedUniversals(filters []string) ([]string, error) {
var prefixedUniversals []string
identities, err := c.resolveIdentities(filters)
if err != nil {
return nil, err
}
for _, identityEntry := range identities {
prefixedUniversals = append(prefixedUniversals, identityEntry.PrefixedUniversal)
}

return prefixedUniversals, nil
}

func (c *Connector) resolveIdentities(filters []string) ([]*IdentityEntry, error) {
var identities []*IdentityEntry
uniqueContacts := getUniqueStringSlice(filters)
for _, contact := range uniqueContacts {
identity, err := c.getIdentity(contact)
identityEntry, err := c.getIdentity(contact)
if err != nil {
return nil, err
}
identities = append(identities, identity.PrefixedUniversal)
identities = append(identities, identityEntry)
}

return identities, nil
Expand All @@ -1215,12 +1242,12 @@ func getUniqueStringSlice(stringSlice []string) []string {
return list
}

func (c *Connector) getIdentity(userName string) (*policy.IdentityEntry, error) {
func (c *Connector) getIdentity(userName string) (*IdentityEntry, error) {
if userName == "" {
return nil, fmt.Errorf("identity string cannot be null")
}

req := policy.BrowseIdentitiesRequest{
req := BrowseIdentitiesRequest{
Filter: userName,
Limit: 2,
IdentityType: policy.AllIdentities,
Expand All @@ -1234,8 +1261,8 @@ func (c *Connector) getIdentity(userName string) (*policy.IdentityEntry, error)
return c.getIdentityMatching(resp.Identities, userName)
}

func (c *Connector) getIdentityMatching(identities []policy.IdentityEntry, identityName string) (*policy.IdentityEntry, error) {
var identityEntryMatching *policy.IdentityEntry
func (c *Connector) getIdentityMatching(identities []IdentityEntry, identityName string) (*IdentityEntry, error) {
var identityEntryMatching *IdentityEntry

if len(identities) > 0 {
for i := range identities {
Expand All @@ -1255,7 +1282,7 @@ func (c *Connector) getIdentityMatching(identities []policy.IdentityEntry, ident
}
}

func (c *Connector) browseIdentities(browseReq policy.BrowseIdentitiesRequest) (*policy.BrowseIdentitiesResponse, error) {
func (c *Connector) browseIdentities(browseReq BrowseIdentitiesRequest) (*BrowseIdentitiesResponse, error) {

statusCode, status, body, err := c.request("POST", urlResourceBrowseIdentities, browseReq)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/venafi/tpp/connector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2330,7 +2330,7 @@ func TestOmitSans(t *testing.T) {
Timeout: 30 * time.Second,
}

tppReq, err := prepareRequest(&req, tpp.zone)
tppReq, err := tpp.prepareRequest(&req, tpp.zone)
if err != nil {
t.Fatal(err)
}
Expand Down
53 changes: 44 additions & 9 deletions pkg/venafi/tpp/tpp.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import (

"github.com/Venafi/vcert/v5/pkg/certificate"
"github.com/Venafi/vcert/v5/pkg/endpoint"
"github.com/Venafi/vcert/v5/pkg/policy"
)

const defaultKeySize = 2048
Expand Down Expand Up @@ -73,7 +72,7 @@ type certificateRequest struct {
State string `json:",omitempty"`
Country string `json:",omitempty"`
SubjectAltNames []sanItem `json:",omitempty"`
Contact string `json:",omitempty"`
Contacts []IdentityEntry `json:",omitempty"`
CASpecificAttributes []nameValuePair `json:",omitempty"`
Origin string `json:",omitempty"`
PKCS10 string `json:",omitempty"`
Expand All @@ -98,8 +97,8 @@ type certificateRetrieveRequest struct {
}

type certificateRetrieveResponse struct {
CertificateData string `json:",omitempty"`
Format string `json:",omitempty"`
CertificateData string `json:",omitempty"`
Filename string `json:",omitempty"`
Status string `json:",omitempty"`
Stage int `json:",omitempty"`
Expand Down Expand Up @@ -158,6 +157,42 @@ type sanItem struct {
Name string `json:""`
}

type IdentityEntry struct {
FullName string `json:",omitempty"`
Name string `json:",omitempty"`
Prefix string `json:",omitempty"`
PrefixedName string `json:",omitempty"`
PrefixedUniversal string `json:",omitempty"`
Type int `json:",omitempty"`
Universal string `json:",omitempty"`
}

type BrowseIdentitiesResponse struct {
Identities []IdentityEntry
}

type IdentitySelfResponse struct {
Identities []IdentityEntry
}

type ValidateIdentityResponse struct {
ID IdentityEntry
}

type BrowseIdentitiesRequest struct {
Filter string
Limit int
IdentityType int
}

type ValidateIdentityRequest struct {
ID IdentityInformation
}

type IdentityInformation struct {
PrefixedUniversal string
}

type nameValuePair struct {
Name string `json:",omitempty"`
Value string `json:",omitempty"`
Expand Down Expand Up @@ -717,8 +752,8 @@ func newPEMCollectionFromResponse(base64Response string, chainOrder certificate.
return nil, nil
}

func parseBrowseIdentitiesResult(httpStatusCode int, httpStatus string, body []byte) (policy.BrowseIdentitiesResponse, error) {
var browseIdentitiesResponse policy.BrowseIdentitiesResponse
func parseBrowseIdentitiesResult(httpStatusCode int, httpStatus string, body []byte) (BrowseIdentitiesResponse, error) {
var browseIdentitiesResponse BrowseIdentitiesResponse
switch httpStatusCode {
case http.StatusOK, http.StatusAccepted:
browseIdentitiesResponse, err := parseBrowseIdentitiesData(body)
Expand All @@ -731,13 +766,13 @@ func parseBrowseIdentitiesResult(httpStatusCode int, httpStatus string, body []b
}
}

func parseBrowseIdentitiesData(b []byte) (data policy.BrowseIdentitiesResponse, err error) {
func parseBrowseIdentitiesData(b []byte) (data BrowseIdentitiesResponse, err error) {
err = json.Unmarshal(b, &data)
return
}

func parseValidateIdentityResponse(httpStatusCode int, httpStatus string, body []byte) (policy.ValidateIdentityResponse, error) {
var validateIdentityResponse policy.ValidateIdentityResponse
func parseValidateIdentityResponse(httpStatusCode int, httpStatus string, body []byte) (ValidateIdentityResponse, error) {
var validateIdentityResponse ValidateIdentityResponse
switch httpStatusCode {
case http.StatusOK, http.StatusAccepted:
validateIdentityResponse, err := parseValidateIdentityData(body)
Expand All @@ -750,7 +785,7 @@ func parseValidateIdentityResponse(httpStatusCode int, httpStatus string, body [
}
}

func parseValidateIdentityData(b []byte) (data policy.ValidateIdentityResponse, err error) {
func parseValidateIdentityData(b []byte) (data ValidateIdentityResponse, err error) {
err = json.Unmarshal(b, &data)
return
}
Expand Down

0 comments on commit cc13171

Please sign in to comment.