-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Extraction of thumbprint value through the certificate #389
feat: Extraction of thumbprint value through the certificate #389
Conversation
Pull Request Test Coverage Report for Build 7131470459
💛 - Coveralls |
libraries/botframework-connector/src/auth/certificateServiceClientCredentialsFactory.ts
Outdated
Show resolved
Hide resolved
libraries/botframework-connector/src/auth/certificateServiceClientCredentialsFactory.ts
Outdated
Show resolved
Hide resolved
libraries/botframework-connector/src/auth/certificateServiceClientCredentialsFactory.ts
Show resolved
Hide resolved
const certString = Buffer.from(cert).toString(); | ||
const begin = certString.lastIndexOf('-----BEGIN CERTIFICATE-----'); | ||
const end = certString.lastIndexOf('-----END CERTIFICATE-----') + '-----END CERTIFICATE-----'.length; | ||
const certificate = certString.slice(begin, end); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to pass the -----BEGIN CERTIFICATE-----
and -----END CERTIFICATE-----
into the openssl function?
- If we dont have to, we could just pass the public certificate value by doing like MSAL is doing internally
/-----BEGIN CERTIFICATE-----\r*\n(.+?)\r*\n-----END CERTIFICATE-----/gs
. - If we need to pass the public cert with the begin and end tags, we could maintain this logic, but put the BEGIN and END tags in variables
- Can the certificate just be past as it is to the openssl function?, i see there is a
Fingerprint
thats being remove after the function execution, if passing the entire certificate as it is, couldnt we just look for that fingerprint and extract its value using for example regex?
libraries/botframework-connector/src/auth/certificateServiceClientCredentialsFactory.ts
Outdated
Show resolved
Hide resolved
* @param tenantId Optional. The oauth token tenant. | ||
* set this parameter to send the public certificate (BEGIN CERTIFICATE) to Azure AD, so that Azure AD can use it to validate the subject name based on a trusted issuer policy. | ||
*/ | ||
constructor(appId: string, certificateThumbprintOrx5c?: string, certificatePrivateKey?: string, tenantId?: string); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The naming of the parameters are confusing here, this naming is only appropriate in the constructor implementation, not the constructor overloading that is visible to the client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that this method is the one that doesnt have the thumbprint, if we can maintain the original constructor behavior in this one by just not including the thumbprint will be ideal.
If for some reason we cant do that, we could move the x5c parameter in the place of the thumbprint which i think you did here.
constructor(appId: string, certificateThumbprintOrx5c?: string, certificatePrivateKey?: string, tenantId?: string) { | ||
super(); | ||
|
||
ok(appId?.trim(), 'CertificateServiceClientCredentialsFactory.constructor(): missing appId.'); | ||
ok( | ||
certificateThumbprint?.trim(), | ||
'CertificateServiceClientCredentialsFactory.constructor(): missing certificateThumbprint.' | ||
certificateThumbprintOrx5c?.trim(), | ||
'CertificateServiceClientCredentialsFactory.constructor(): missing certificateThumbprint or x5c value.' | ||
); | ||
ok( | ||
certificatePrivateKey?.trim(), | ||
'CertificateServiceClientCredentialsFactory.constructor(): missing certificatePrivateKey.' | ||
); | ||
|
||
this.appId = appId; | ||
this.certificateThumbprint = certificateThumbprint; | ||
this.certificateThumbprint = certificateThumbprintOrx5c?.length <= 40 ? certificateThumbprintOrx5c : undefined; | ||
this.certificatePrivateKey = certificatePrivateKey; | ||
this.tenantId = tenantId; | ||
this.x5c = x5c; | ||
this.x5c = certificateThumbprintOrx5c?.length > 40 ? certificateThumbprintOrx5c : undefined; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By changing the declaration of the previous constructors, this implementation will also change.
The use of the condition <= 40
is not really good in my opinion to determine if it is a thumbprint or a x5c, this size could change in a future, and could start failing without knowing. We need to find a better approach.
An idea i just think of is to, leave the original constructor as it was and just create the new one, it will be a difference of 1 parameter, if that parameter is undefined use one or the other, the only problem i see with this is that the user pass undefined in that last variable when some external function retrieved the x5c value as undefined an just pass it to this function.
Another option could be detecting if the value passed in the parameter is a x5c, i believe that this we already have it, detecting if it has the BEGIN CERTIFICATE or something like that.
Another option could be combining the two
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean with "leave the original constructor as it was and just create the new one"?
I have two options for this:
- Leave the parameters like the previous one:
(appId: string, certificateThumbprint: string, certificatePrivateKey: string, tenantId?: string, x5c: string,)
And the user will have to send this ("appId", "", "key", "tenant", "x5c") - Use the includes function with BEGIN CERTIFICATE to validate the x5c value
I would rather the second one
ok( | ||
certificateThumbprintOrx5c.trim(), | ||
'CertificateServiceClientCredentialsFactory.constructor(): missing x5c.' | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now looking at this, this validation will not be triggered anymore, because will fail if the certificateThumbprintOrx5c is empty, which will not be the case.
And add in the else in the validation the or x5c
like you had before because we dont know if it is the thumbprint or the x5c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more comment to apply from Joel. The rest LGTM
4927b70
to
8803011
Compare
Promoted /4580 |
#minor
Description
This PR allows the creation of an object of the CertificateServiceClientCredentialsFactory class using only the values:
In addition to being able to get the thumbprint value through the certificate when creating the credentials.
Specific Changes
Testing
The following image shows the bot running with SNI authentication.
This is the configuration required to use the SNI authentication.