Skip to content

Commit 6e7e561

Browse files
authored
extractServicePrincipal api for java/go (AthenZ#593)
1 parent bcd2020 commit 6e7e561

28 files changed

+524
-30
lines changed

libs/go/ztsclientutil/Makefile libs/go/athenzutils/Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# Licensed under the Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0
77
#
88

9-
GOPKGNAME = github.com/yahoo/athenz/libs/go/ztsclientutil
9+
GOPKGNAME = github.com/yahoo/athenz/libs/go/athenzutils
1010

1111
# check to see if go utility is installed
1212
GO := $(shell command -v go 2> /dev/null)
@@ -43,7 +43,7 @@ fmt:
4343
gofmt -l .
4444

4545
build:
46-
@echo "Building ztsclientutil library..."
46+
@echo "Building athenzutils library..."
4747
go install -v $(GOPKGNAME)
4848

4949
test:

libs/go/ztsclientutil/README.md libs/go/athenzutils/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
ztsclientutil
1+
athenzutils
22
===========
33

44
Go library to return zts client given private key and certificate.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICVzCCAgGgAwIBAgIJAPnPBCVtXBIQMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNV
3+
BAYTAlVTMQswCQYDVQQIEwJDQTEPMA0GA1UEChMGQXRoZW56MRcwFQYDVQQLEw5U
4+
ZXN0aW5nIERvbWFpbjEfMB0GA1UEAxMWYXRoZW56OnJvbGUucHJvZHVjdGlvbjAe
5+
Fw0xODExMDkwMTI0NDdaFw0yODExMDYwMTI0NDdaMGUxCzAJBgNVBAYTAlVTMQsw
6+
CQYDVQQIEwJDQTEPMA0GA1UEChMGQXRoZW56MRcwFQYDVQQLEw5UZXN0aW5nIERv
7+
bWFpbjEfMB0GA1UEAxMWYXRoZW56OnJvbGUucHJvZHVjdGlvbjBcMA0GCSqGSIb3
8+
DQEBAQUAA0sAMEgCQQDDpJJEX7QFGTynqGYn7CxIKxVYU7YXBYF4XYmVJM5/bBa1
9+
jP9uslVbMxEiaPZVq1vgVdKVZAKoOg2/sp/RvlDXAgMBAAGjgZMwgZAwgY0GA1Ud
10+
EQSBhTCBgoIjcHJvZHVjdGlvbi5hdGhlbnoub3N0ay5hdGhlbnouY2xvdWSCKDEw
11+
MDEuaW5zdGFuY2VpZC5hdGhlbnoub3N0ay5hdGhlbnouY2xvdWSHBAoLDA2HBAoL
12+
DA6GFnNwaWZmZTovL2F0aGVuei9zYS9hcGmBDWF0aGVuei5zeW5jZXIwDQYJKoZI
13+
hvcNAQELBQADQQB8feFwhj2hAhJngIEckh5Hq1kwTH4BZH9gEXNp3fQ/a1CxbveS
14+
xfjMGaZKGglVtzDICXxv86QAytgjDPBTRCy9
15+
-----END CERTIFICATE-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICiTCCAjOgAwIBAgIJALYCFietAJw2MA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNV
3+
BAYTAlVTMQswCQYDVQQIEwJDQTEPMA0GA1UEChMGQXRoZW56MRcwFQYDVQQLEw5U
4+
ZXN0aW5nIERvbWFpbjEfMB0GA1UEAxMWYXRoZW56OnJvbGUucHJvZHVjdGlvbjAe
5+
Fw0xODExMDkwMTIzMDdaFw0yODExMDYwMTIzMDdaMGUxCzAJBgNVBAYTAlVTMQsw
6+
CQYDVQQIEwJDQTEPMA0GA1UEChMGQXRoZW56MRcwFQYDVQQLEw5UZXN0aW5nIERv
7+
bWFpbjEfMB0GA1UEAxMWYXRoZW56OnJvbGUucHJvZHVjdGlvbjBcMA0GCSqGSIb3
8+
DQEBAQUAA0sAMEgCQQC06s0rPkxZHvgeCNkzOf66AyP+96yWnojraO7Dus9tAGZ9
9+
6Lx7GcTBaXwlqE6wSITegi8YCOZJTnD8k6nKAQjBAgMBAAGjgcUwgcIwgb8GA1Ud
10+
EQSBtzCBtIIjcHJvZHVjdGlvbi5hdGhlbnoub3N0ay5hdGhlbnouY2xvdWSCKDEw
11+
MDEuaW5zdGFuY2VpZC5hdGhlbnoub3N0ay5hdGhlbnouY2xvdWSHBAoLDA2HBAoL
12+
DA6GFnNwaWZmZTovL2F0aGVuei9zYS9hcGmBHmF0aGVuei5zeW5jZXJAenRzLmF0
13+
aGVuei5jbG91ZIEfYXRoZW56LnN5bmNlcjJAenRzLmF0aGVuei5jbG91ZDANBgkq
14+
hkiG9w0BAQsFAANBAKIO6IZu+dg/QDN3RPAW4J+mwODZRFwF6eoRRPZwisOSw0m0
15+
InN3TNCbJXaMkCDHklRC+Dw8d61fH+Jd7f5XrW4=
16+
-----END CERTIFICATE-----
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICAjCCAaygAwIBAgIJAKVAwSLBk5aQMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNV
3+
BAYTAlVTMQswCQYDVQQIEwJDQTEPMA0GA1UEChMGQXRoZW56MRcwFQYDVQQLEw5U
4+
ZXN0aW5nIERvbWFpbjAeFw0xODExMDkwMTIwNDFaFw0yODExMDYwMTIwNDFaMEQx
5+
CzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEPMA0GA1UEChMGQXRoZW56MRcwFQYD
6+
VQQLEw5UZXN0aW5nIERvbWFpbjBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDKPeQm
7+
YFqHgwjZEeeN06E2DG3J2f6UN/7HzOkxymRPnz1D0LqEPoPZFuPljyCWLIKLQntK
8+
TioluTbhF0UrZi2vAgMBAAGjgYAwfjB8BgNVHREEdTBzgiNwcm9kdWN0aW9uLmF0
9+
aGVuei5vc3RrLmF0aGVuei5jbG91ZIIoMTAwMS5pbnN0YW5jZWlkLmF0aGVuei5v
10+
c3RrLmF0aGVuei5jbG91ZIcECgsMDYcECgsMDoYWc3BpZmZlOi8vYXRoZW56L3Nh
11+
L2FwaTANBgkqhkiG9w0BAQsFAANBACQLqyjGuhWhtj4c8gDOpQy6JQch4NbgK6eW
12+
lVxjPLkN/N5okddDAUNJBeI6b4K2Jqhi9dGs1SMKowEpVXFBTmc=
13+
-----END CERTIFICATE-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICRDCCAe6gAwIBAgIJAOjFRfavoMeyMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNV
3+
BAYTAlVTMQswCQYDVQQIEwJDQTEPMA0GA1UEChMGQXRoZW56MRcwFQYDVQQLEw5U
4+
ZXN0aW5nIERvbWFpbjEfMB0GA1UEAxMWYXRoZW56OnJvbGUucHJvZHVjdGlvbjAe
5+
Fw0xODExMDkwMTIxNTFaFw0yODExMDYwMTIxNTFaMGUxCzAJBgNVBAYTAlVTMQsw
6+
CQYDVQQIEwJDQTEPMA0GA1UEChMGQXRoZW56MRcwFQYDVQQLEw5UZXN0aW5nIERv
7+
bWFpbjEfMB0GA1UEAxMWYXRoZW56OnJvbGUucHJvZHVjdGlvbjBcMA0GCSqGSIb3
8+
DQEBAQUAA0sAMEgCQQD9CDZYikP0sK08fGZkfM1JrVcxUOgxDjPkcxQfxdJ5Cr0v
9+
URytQ1or8Ziq6OtL4DlUoj5HT6Eudi38Ik88H1sDAgMBAAGjgYAwfjB8BgNVHREE
10+
dTBzgiNwcm9kdWN0aW9uLmF0aGVuei5vc3RrLmF0aGVuei5jbG91ZIIoMTAwMS5p
11+
bnN0YW5jZWlkLmF0aGVuei5vc3RrLmF0aGVuei5jbG91ZIcECgsMDYcECgsMDoYW
12+
c3BpZmZlOi8vYXRoZW56L3NhL2FwaTANBgkqhkiG9w0BAQsFAANBAGh9Yd09DX/X
13+
OPHE9oBvP1X2x8MBos8Iw98Uja2Ul669ym/6DTGE+3+BBVXn84ZncBMfK2NmoKGL
14+
Vf6ohlA02M4=
15+
-----END CERTIFICATE-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIB6zCCAZWgAwIBAgIJAOHhVUnRILR3MA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV
3+
BAYTAlVTMQswCQYDVQQIEwJDQTEPMA0GA1UEChMGQXRoZW56MRcwFQYDVQQLEw5U
4+
ZXN0aW5nIERvbWFpbjEaMBgGA1UEAxMRYXRoZW56LnByb2R1Y3Rpb24wHhcNMTgw
5+
OTIwMjIyODMyWhcNMjgwOTE3MjIyODMyWjBgMQswCQYDVQQGEwJVUzELMAkGA1UE
6+
CBMCQ0ExDzANBgNVBAoTBkF0aGVuejEXMBUGA1UECxMOVGVzdGluZyBEb21haW4x
7+
GjAYBgNVBAMTEWF0aGVuei5wcm9kdWN0aW9uMFwwDQYJKoZIhvcNAQEBBQADSwAw
8+
SAJBAMHYmM1iXRMiA9SWhUWR/l09b0RBR2z50NdUVQ0251jmwrcqudAH93dc8WPo
9+
4N8o0/pmLpj8MxkZpYBNlr6fns0CAwEAAaMyMDAwLgYDVR0RAQH/BCQwIoYgc3Bp
10+
ZmZlOi8vYXRoZW56L2RvbWFpbjEvc2VydmljZTEwDQYJKoZIhvcNAQELBQADQQCf
11+
V/b+rXPQHJuFR8OzwJ8YciAcdNn0ujXck+rAvxylN75tcolXW2JqxOwO4GIONJFn
12+
E/iThKWdVOkpccxuJKf0
13+
-----END CERTIFICATE-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICejCCAiKgAwIBAgIJAKxhW5mQ2i8xMAkGByqGSM49BAEwYDELMAkGA1UEBhMC
3+
VVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlTdW5ueXZhbGUxGDAWBgNVBAoTD015
4+
IFRlc3QgQ29tcGFueTEWMBQGA1UEAxMNYXRoZW56LnN5bmNlcjAeFw0xNjEyMDky
5+
MjA0NTdaFw0xNzEyMDkyMjA0NTdaMGAxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJD
6+
QTESMBAGA1UEBxMJU3Vubnl2YWxlMRgwFgYDVQQKEw9NeSBUZXN0IENvbXBhbnkx
7+
FjAUBgNVBAMTDWF0aGVuei5zeW5jZXIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
8+
AASNMesBFJOU9IbJWk/NwzVcua/fF5xuxwI0Mp4wq3HQngE3Vdnm6Xn6gZYv0l2c
9+
Ly9/uzog9zE68hm0fs0UhWf7o4HFMIHCMB0GA1UdDgQWBBRzUG6PZe6W5zH0hYKu
10+
OAFCNbpU6TCBkgYDVR0jBIGKMIGHgBRzUG6PZe6W5zH0hYKuOAFCNbpU6aFkpGIw
11+
YDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlTdW5ueXZhbGUx
12+
GDAWBgNVBAoTD015IFRlc3QgQ29tcGFueTEWMBQGA1UEAxMNYXRoZW56LnN5bmNl
13+
coIJAKxhW5mQ2i8xMAwGA1UdEwQFMAMBAf8wCQYHKoZIzj0EAQNHADBEAiBY+KCi
14+
NMjkPod8Cx9Iufy9sfPjohEsWtjhAhLpDDgxxgIgaaKNCn7SIWYyelqyn41VMazv
15+
4oAZqrR8bLL/qllF0bg=
16+
-----END CERTIFICATE-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIB5zCCAZGgAwIBAgIJAJfJZq1is0dQMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNV
3+
BAYTAlVTMQswCQYDVQQIEwJDQTEPMA0GA1UEChMGQXRoZW56MRcwFQYDVQQLEw5U
4+
ZXN0aW5nIERvbWFpbjEcMBoGA1UEAxMTc3BvcnRzOnJvbGUucmVhZGVyczAeFw0x
5+
NzA2MDgyMjQ5MDhaFw0yNzA2MDYyMjQ5MDhaMGIxCzAJBgNVBAYTAlVTMQswCQYD
6+
VQQIEwJDQTEPMA0GA1UEChMGQXRoZW56MRcwFQYDVQQLEw5UZXN0aW5nIERvbWFp
7+
bjEcMBoGA1UEAxMTc3BvcnRzOnJvbGUucmVhZGVyczBcMA0GCSqGSIb3DQEBAQUA
8+
A0sAMEgCQQDmMlj3Ov0k/FEH7iK3VpgUFEp6KrCWegWNieG8/b+FJymUP5zL4lwn
9+
lk35Wa7SmZ6KjCn5Lo37fSdWMtoq375ZAgMBAAGjKjAoMCYGA1UdEQQfMB2BG2F0
10+
aGVucy56dHNAYXdzLmF0aGVuei5jbG91ZDANBgkqhkiG9w0BAQsFAANBACJ/oKfs
11+
6melTAC2E6iEpXpA8HRguTHNQFYiwhaYBazfXkL0zrtX2mKFT8yG2AtWw0+w9A0u
12+
SXShdpDmz9y2kPY=
13+
-----END CERTIFICATE-----
File renamed without changes.

libs/go/athenzutils/principal.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2018 Oath, Inc.
2+
// Licensed under the terms of the Apache version 2.0 license. See LICENSE file for terms.
3+
4+
package athenzutils
5+
6+
import (
7+
"crypto/x509"
8+
"fmt"
9+
"strings"
10+
)
11+
12+
// Return the Athenz Service principal for the given certificate which
13+
// could be either a service certificate or a role certificate.
14+
// If the certificate does not have the Athenz expected name format
15+
// the method will an appropriate error
16+
17+
func ExtractServicePrincipal(x509Cert x509.Certificate) (string, error) {
18+
19+
// let's first get the common name of the certificate
20+
21+
principal := x509Cert.Subject.CommonName
22+
if principal == "" {
23+
return "", fmt.Errorf("certificate does not have a common name")
24+
}
25+
26+
// check to see if we're dealing with role certificate which
27+
// has the <domain>:role.<rolename> format or service
28+
// certificate which has the <domain>.<service> format
29+
30+
if strings.Contains(principal, ":role.") {
31+
32+
// it's a role certificate so we're going to extract
33+
// our service principal from the SAN email fieid
34+
// verify that we must have only a single email
35+
// field in the certificate
36+
37+
emails := x509Cert.EmailAddresses
38+
if len(emails) != 1 {
39+
return "", fmt.Errorf("certificate does not have a single email SAN value")
40+
}
41+
42+
// athenz always verifies that we include a valid
43+
// email in the certificate
44+
45+
idx := strings.Index(emails[0], "@")
46+
if idx == -1 {
47+
return "", fmt.Errorf("certificate email is invalid: %s", emails[0])
48+
}
49+
50+
principal = emails[0][0:idx]
51+
}
52+
53+
return principal, nil
54+
}

libs/go/athenzutils/principal_test.go

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2018 Oath, Inc.
2+
// Licensed under the terms of the Apache version 2.0 license. See LICENSE file for terms.
3+
4+
package athenzutils
5+
6+
import (
7+
"crypto/x509"
8+
"encoding/pem"
9+
"io/ioutil"
10+
"testing"
11+
)
12+
13+
func TestExtractServicePrincipal(test *testing.T) {
14+
15+
x509Cert, _ := getCertFromFile("data/service_identity1.cert")
16+
principal, _ := ExtractServicePrincipal(*x509Cert)
17+
if principal != "athenz.production" {
18+
test.Errorf("invalid principal %s from data/service_identity1.cert", principal)
19+
}
20+
21+
x509Cert, _ = getCertFromFile("data/service_identity2.cert")
22+
principal, _ = ExtractServicePrincipal(*x509Cert)
23+
if principal != "athenz.syncer" {
24+
test.Errorf("invalid principal %s from data/service_identity2.cert", principal)
25+
}
26+
27+
x509Cert, _ = getCertFromFile("data/valid_email_x509.cert")
28+
principal, _ = ExtractServicePrincipal(*x509Cert)
29+
if principal != "athens.zts" {
30+
test.Errorf("invalid principal %s from data/valid_email.cert", principal)
31+
}
32+
33+
x509Cert, _ = getCertFromFile("data/no_cn_x509.cert")
34+
principal, err := ExtractServicePrincipal(*x509Cert)
35+
if err == nil {
36+
test.Errorf("no error from invalid file data/no_cn_x509.cert: %s", principal)
37+
}
38+
39+
x509Cert, _ = getCertFromFile("data/invalid_email_x509.cert")
40+
principal, err = ExtractServicePrincipal(*x509Cert)
41+
if err == nil {
42+
test.Errorf("no error from invalid file data/invalid_email_x509.cert: %s", principal)
43+
}
44+
45+
x509Cert, _ = getCertFromFile("data/multiple_email_x509.cert")
46+
principal, err = ExtractServicePrincipal(*x509Cert)
47+
if err == nil {
48+
test.Errorf("no error from invalid file data/multiple_email_x509.cert: %s", principal)
49+
}
50+
51+
x509Cert, _ = getCertFromFile("data/no_email_x509.cert")
52+
principal, err = ExtractServicePrincipal(*x509Cert)
53+
if err == nil {
54+
test.Errorf("no error from invalid file data/no_email_x509.cert: %s", principal)
55+
}
56+
}
57+
58+
func getCertFromFile(certFile string) (*x509.Certificate, error) {
59+
data, err := ioutil.ReadFile(certFile)
60+
if err != nil {
61+
return nil, err
62+
}
63+
var block *pem.Block
64+
block, _ = pem.Decode(data)
65+
return x509.ParseCertificate(block.Bytes)
66+
}

libs/go/ztsclientutil/ztsclient.go libs/go/athenzutils/ztsclient.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2018 Yahoo Holdings, Inc.
22
// Licensed under the terms of the Apache version 2.0 license. See LICENSE file for terms.
33

4-
package ztsclientutil
4+
package athenzutils
55

66
import (
77
"crypto/tls"

libs/java/auth_core/pom.xml

-5
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@
3737
<artifactId>libpam4j</artifactId>
3838
<version>1.11</version>
3939
</dependency>
40-
<dependency>
41-
<groupId>com.amazonaws</groupId>
42-
<artifactId>aws-java-sdk-s3</artifactId>
43-
<version>${aws.version}</version>
44-
</dependency>
4540
<dependency>
4641
<groupId>javax.servlet</groupId>
4742
<artifactId>javax.servlet-api</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2018 Oath Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.yahoo.athenz.auth.util;
17+
18+
import java.security.cert.X509Certificate;
19+
import java.util.List;
20+
21+
public class AthenzUtils {
22+
23+
/**
24+
* Return the Athenz Service principal for the given certificate which
25+
* could be either a service certificate or a role certificate.
26+
* If the certificate does not have the Athenz expected name format
27+
* the method will return null.
28+
* @param x509Cert x.509 athenz service or role certificate
29+
* @return service principal cn
30+
*/
31+
public static String extractServicePrincipal(X509Certificate x509Cert) {
32+
33+
// let's first get the common name of the certificate
34+
35+
String principal = Crypto.extractX509CertCommonName(x509Cert);
36+
if (principal == null) {
37+
return null;
38+
}
39+
40+
// check to see if we're dealing with role certificate which
41+
// has the <domain>:role.<rolename> format or service
42+
// certificate which has the <domain>.<service> format
43+
44+
if (principal.contains(":role.")) {
45+
46+
// it's a role certificate so we're going to extract
47+
// our service principal from the SAN email fieid
48+
// verify that we must have only a single email
49+
// field in the certificate
50+
51+
final List<String> emails = Crypto.extractX509CertEmails(x509Cert);
52+
if (emails.size() != 1) {
53+
return null;
54+
}
55+
56+
// athenz always verifies that we include a valid
57+
// email in the certificate
58+
59+
final String email = emails.get(0);
60+
int idx = email.indexOf('@');
61+
if (idx == -1) {
62+
return null;
63+
}
64+
65+
principal = email.substring(0, idx);
66+
}
67+
68+
return principal;
69+
}
70+
}

0 commit comments

Comments
 (0)