in src/blob/authentication/BlobSASAuthenticator.ts [33:226]
public async validate(
req: IRequest,
context: Context
): Promise<boolean | undefined> {
this.logger.info(
`BlobSASAuthenticator:validate() Start validation against blob service Shared Access Signature pattern.`,
context.contextId
);
this.logger.debug(
"BlobSASAuthenticator:validate() Getting account properties...",
context.contextId
);
const blobContext = new BlobStorageContext(context);
const account = blobContext.account;
if (account === undefined) {
throw RangeError(
`BlobSASAuthenticator:validate() account is undefined in context.`
);
}
const containerName = blobContext.container;
if (containerName === undefined) {
this.logger.error(
`BlobSASAuthenticator:validate() container name is undefined in context.`,
context.contextId
);
return undefined;
}
const blobName = blobContext.blob;
this.logger.debug(
// tslint:disable-next-line:max-line-length
`BlobSASAuthenticator:validate() Retrieved account name from context: ${account}, container: ${containerName}, blob: ${blobName}`,
context.contextId
);
// TODO: Make following async
const accountProperties = this.accountDataStore.getAccount(account);
if (accountProperties === undefined) {
throw StorageErrorFactory.ResourceNotFound(
blobContext.contextId!
);
}
this.logger.debug(
"BlobSASAuthenticator:validate() Got account properties successfully.",
context.contextId
);
// Extract blob service SAS authentication required parameters
const signature = this.decodeIfExist(req.getQuery("sig"));
this.logger.debug(
`BlobSASAuthenticator:validate() Retrieved signature from URL parameter sig: ${signature}`,
context.contextId
);
if (signature === undefined) {
this.logger.debug(
`BlobSASAuthenticator:validate() No signature found in request. Skip blob service SAS validation.`,
context.contextId
);
return undefined;
}
const resource = this.decodeIfExist(req.getQuery("sr"));
if (
resource !== BlobSASResourceType.Container &&
resource !== BlobSASResourceType.Blob &&
resource !== BlobSASResourceType.BlobSnapshot
) {
this.logger.debug(
// tslint:disable-next-line:max-line-length
`BlobSASAuthenticator:validate() Signed resource type ${resource} is invalid. Skip blob service SAS validation.`,
context.contextId
);
return undefined;
}
this.logger.debug(
`BlobSASAuthenticator:validate() Signed resource type is ${resource}.`,
context.contextId
);
const values = this.getBlobSASSignatureValuesFromRequest(
req,
containerName,
blobName,
context
);
if (values === undefined) {
this.logger.info(
// tslint:disable-next-line:max-line-length
`BlobSASAuthenticator:validate() Failed to get valid blob service SAS values from request. Skip blob service SAS validation.`,
context.contextId
);
return undefined;
}
this.logger.debug(
`BlobSASAuthenticator:validate() Successfully got valid blob service SAS values from request. ${JSON.stringify(
values
)}`,
context.contextId
);
if (!context.context.loose && values.encryptionScope !== undefined)
{
throw new StrictModelNotSupportedError("SAS Encryption Scope 'ses'", context.contextId);
}
if (values.signedObjectId
|| values.signedTenantId
|| values.signedService
|| values.signedVersion
|| values.signedStartsOn
|| values.signedExpiresOn) {
this.logger.info(
`BlobSASAuthenticator:validate() Validate signature based on user delegation key.`,
context.contextId
);
if (!values.signedObjectId
|| !values.signedTenantId
|| !values.signedStartsOn
|| !values.signedExpiresOn
|| !values.signedService
|| !values.signedVersion
|| values.signedService !== "b") {
this.logger.info(
`BlobSASAuthenticator:validate() Signature based on user delegation key validation failed"
}.`,
context.contextId
);
throw StorageErrorFactory.getAuthorizationFailure(context.contextId!);
}
const savedPolicy = this.decodeIfExist(req.getQuery("si"));
if (savedPolicy) {
this.logger.info(
`BlobSASAuthenticator:validate() Access policy used in UDK SAS.`,
context.contextId
);
throw StorageErrorFactory.getAuthorizationFailure(context.contextId!);
}
this.logger.info(
`BlobSASAuthenticator:validate() Validate UDK start and expiry time.`,
context.contextId
);
if (!this.validateTime(values.signedExpiresOn!, values.signedStartsOn!)) {
this.logger.info(
`BlobSASAuthenticator:validate() Validate UDK start and expiry failed.`,
context.contextId
);
throw StorageErrorFactory.getAuthorizationFailure(context.contextId!);
}
const keyValue = getUserDelegationKeyValue(
values.signedObjectId!,
values.signedTenantId!,
values.signedStartsOn!,
values.signedExpiresOn!,
values.signedVersion!
);
const [sig, stringToSign] = generateBlobSASSignatureWithUDK(
values,
resource,
account,
Buffer.from(keyValue, "base64")
);
this.logger.debug(
`BlobSASAuthenticator:validate() String to sign is: ${JSON.stringify(
stringToSign
)}`,
context.contextId!
);
this.logger.debug(
`BlobSASAuthenticator:validate() Calculated signature is: ${sig}`,
context.contextId!
);
const sigPass = sig === signature;
this.logger.info(
`BlobSASAuthenticator:validate() Signature based on UDK ${
sigPass ? "passed" : "failed"
}.`,
context.contextId
);
if (!sigPass) {
return sigPass;
}
}