Add organizationalUnit to passtlscert middleware

This commit is contained in:
Eric 2021-07-28 16:42:09 +01:00 committed by GitHub
parent c76d58d532
commit 817ac8f256
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 339 additions and 157 deletions

View file

@ -35,8 +35,10 @@ var attributeTypeNames = map[string]string{
"0.9.2342.19200300.100.1.25": "DC", // Domain component OID - RFC 2247
}
// DistinguishedNameOptions is a struct for specifying the configuration for the distinguished name info.
type DistinguishedNameOptions struct {
// IssuerDistinguishedNameOptions is a struct for specifying the configuration
// for the distinguished name info of the issuer. This information is defined in
// RFC3739, section 3.1.1.
type IssuerDistinguishedNameOptions struct {
CommonName bool
CountryName bool
DomainComponent bool
@ -46,12 +48,12 @@ type DistinguishedNameOptions struct {
StateOrProvinceName bool
}
func newDistinguishedNameOptions(info *dynamic.TLSCLientCertificateDNInfo) *DistinguishedNameOptions {
func newIssuerDistinguishedNameOptions(info *dynamic.TLSCLientCertificateIssuerDNInfo) *IssuerDistinguishedNameOptions {
if info == nil {
return nil
}
return &DistinguishedNameOptions{
return &IssuerDistinguishedNameOptions{
CommonName: info.CommonName,
CountryName: info.Country,
DomainComponent: info.DomainComponent,
@ -62,13 +64,44 @@ func newDistinguishedNameOptions(info *dynamic.TLSCLientCertificateDNInfo) *Dist
}
}
// SubjectDistinguishedNameOptions is a struct for specifying the configuration
// for the distinguished name info of the subject. This information is defined
// in RFC3739, section 3.1.2.
type SubjectDistinguishedNameOptions struct {
CommonName bool
CountryName bool
DomainComponent bool
LocalityName bool
OrganizationName bool
OrganizationalUnitName bool
SerialNumber bool
StateOrProvinceName bool
}
func newSubjectDistinguishedNameOptions(info *dynamic.TLSCLientCertificateSubjectDNInfo) *SubjectDistinguishedNameOptions {
if info == nil {
return nil
}
return &SubjectDistinguishedNameOptions{
CommonName: info.CommonName,
CountryName: info.Country,
DomainComponent: info.DomainComponent,
LocalityName: info.Locality,
OrganizationName: info.Organization,
OrganizationalUnitName: info.OrganizationalUnit,
SerialNumber: info.SerialNumber,
StateOrProvinceName: info.Province,
}
}
// tlsClientCertificateInfo is a struct for specifying the configuration for the passTLSClientCert middleware.
type tlsClientCertificateInfo struct {
notAfter bool
notBefore bool
sans bool
subject *DistinguishedNameOptions
issuer *DistinguishedNameOptions
subject *SubjectDistinguishedNameOptions
issuer *IssuerDistinguishedNameOptions
serialNumber bool
}
@ -78,10 +111,10 @@ func newTLSClientCertificateInfo(info *dynamic.TLSClientCertificateInfo) *tlsCli
}
return &tlsClientCertificateInfo{
issuer: newDistinguishedNameOptions(info.Issuer),
issuer: newIssuerDistinguishedNameOptions(info.Issuer),
notAfter: info.NotAfter,
notBefore: info.NotBefore,
subject: newDistinguishedNameOptions(info.Subject),
subject: newSubjectDistinguishedNameOptions(info.Subject),
serialNumber: info.SerialNumber,
sans: info.Sans,
}
@ -147,12 +180,12 @@ func (p *passTLSClientCert) getCertInfo(ctx context.Context, certs []*x509.Certi
var values []string
if p.info != nil {
subject := getDNInfo(ctx, p.info.subject, &peerCert.Subject)
subject := getSubjectDNInfo(ctx, p.info.subject, &peerCert.Subject)
if subject != "" {
values = append(values, fmt.Sprintf(`Subject="%s"`, strings.TrimSuffix(subject, subFieldSeparator)))
}
issuer := getDNInfo(ctx, p.info.issuer, &peerCert.Issuer)
issuer := getIssuerDNInfo(ctx, p.info.issuer, &peerCert.Issuer)
if issuer != "" {
values = append(values, fmt.Sprintf(`Issuer="%s"`, strings.TrimSuffix(issuer, subFieldSeparator)))
}
@ -187,7 +220,7 @@ func (p *passTLSClientCert) getCertInfo(ctx context.Context, certs []*x509.Certi
return strings.Join(headerValues, certSeparator)
}
func getDNInfo(ctx context.Context, options *DistinguishedNameOptions, cs *pkix.Name) string {
func getIssuerDNInfo(ctx context.Context, options *IssuerDistinguishedNameOptions, cs *pkix.Name) string {
if options == nil {
return ""
}
@ -229,6 +262,52 @@ func getDNInfo(ctx context.Context, options *DistinguishedNameOptions, cs *pkix.
return content.String()
}
func getSubjectDNInfo(ctx context.Context, options *SubjectDistinguishedNameOptions, cs *pkix.Name) string {
if options == nil {
return ""
}
content := &strings.Builder{}
// Manage non standard attributes
for _, name := range cs.Names {
// Domain Component - RFC 2247
if options.DomainComponent && attributeTypeNames[name.Type.String()] == "DC" {
content.WriteString(fmt.Sprintf("DC=%s%s", name.Value, subFieldSeparator))
}
}
if options.CountryName {
writeParts(ctx, content, cs.Country, "C")
}
if options.StateOrProvinceName {
writeParts(ctx, content, cs.Province, "ST")
}
if options.LocalityName {
writeParts(ctx, content, cs.Locality, "L")
}
if options.OrganizationName {
writeParts(ctx, content, cs.Organization, "O")
}
if options.OrganizationalUnitName {
writeParts(ctx, content, cs.OrganizationalUnit, "OU")
}
if options.SerialNumber {
writePart(ctx, content, cs.SerialNumber, "SN")
}
if options.CommonName {
writePart(ctx, content, cs.CommonName, "CN")
}
return content.String()
}
func writeParts(ctx context.Context, content io.StringWriter, entries []string, prefix string) {
for _, entry := range entries {
writePart(ctx, content, entry, prefix)