@@ -13,6 +13,11 @@ const QUEUE_PORT = 10001;
1313const TABLE_PORT = 10002 ;
1414const DEFAULT_ACCOUNT_NAME = "devstoreaccount1" ;
1515const DEFAULT_ACCOUNT_KEY = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" ;
16+ const PEM_CERT_PATH = "/azurite-cert.pem" ;
17+ const PEM_KEY_PATH = "/azurite-key.pem" ;
18+ const PFX_CERT_PATH = "/azurite-cert.pfx" ;
19+
20+ type Protocol = "http" | "https" ;
1621
1722export class AzuriteContainer extends GenericContainer {
1823 constructor ( image : string ) {
@@ -38,6 +43,11 @@ export class AzuriteContainer extends GenericContainer {
3843 private skipApiVersionCheck = false ;
3944 private inMemoryPersistence = false ;
4045 private extentMemoryLimitInMegaBytes ?: number = undefined ;
46+ private cert ?: string = undefined ;
47+ private certPath ?: string = undefined ;
48+ private key ?: string = undefined ;
49+ private password ?: string = undefined ;
50+ private oauthEnabled = false ;
4151
4252 /**
4353 * Sets a custom storage account name (default account will be disabled).
@@ -112,9 +122,49 @@ export class AzuriteContainer extends GenericContainer {
112122 return this ;
113123 }
114124
125+ /**
126+ * Configure SSL with a custom certificate and private key.
127+ *
128+ * @param cert The PEM certificate file content.
129+ * @param key The PEM key file content.
130+ */
131+ public withSsl ( cert : string , key : string ) : this {
132+ this . cert = cert ;
133+ this . key = key ;
134+ this . password = undefined ;
135+ this . certPath = PEM_CERT_PATH ;
136+ return this ;
137+ }
138+
139+ /**
140+ * Configure SSL with a custom certificate and password.
141+ *
142+ * @param cert The PFX certificate file content.
143+ * @param password The password securing the certificate.
144+ */
145+ public withSslPfx ( cert : string , password : string ) : this {
146+ this . cert = cert ;
147+ this . key = undefined ;
148+ this . password = password ;
149+ this . certPath = PFX_CERT_PATH ;
150+ return this ;
151+ }
152+
153+ /**
154+ * Enable OAuth authentication with basic mode.
155+ */
156+ public withOAuth ( ) : this {
157+ this . oauthEnabled = true ;
158+ return this ;
159+ }
160+
115161 public override async start ( ) : Promise < StartedAzuriteContainer > {
116162 const command = [ "--blobHost" , "0.0.0.0" , "--queueHost" , "0.0.0.0" , "--tableHost" , "0.0.0.0" ] ;
117163
164+ if ( this . oauthEnabled && this . cert === undefined ) {
165+ throw new Error ( "OAuth requires HTTPS endpoint. Configure SSL first with withSsl() or withSslPfx()." ) ;
166+ }
167+
118168 if ( this . inMemoryPersistence ) {
119169 command . push ( "--inMemoryPersistence" ) ;
120170
@@ -127,6 +177,37 @@ export class AzuriteContainer extends GenericContainer {
127177 command . push ( "--skipApiVersionCheck" ) ;
128178 }
129179
180+ if ( this . cert !== undefined && this . certPath !== undefined ) {
181+ const contentsToCopy = [
182+ {
183+ content : this . cert ,
184+ target : this . certPath ,
185+ mode : 0o644 ,
186+ } ,
187+ ] ;
188+
189+ if ( this . key ) {
190+ contentsToCopy . push ( {
191+ content : this . key ,
192+ target : PEM_KEY_PATH ,
193+ mode : 0o600 ,
194+ } ) ;
195+ }
196+
197+ this . withCopyContentToContainer ( contentsToCopy ) ;
198+ command . push ( "--cert" , this . certPath ) ;
199+
200+ if ( this . key ) {
201+ command . push ( "--key" , PEM_KEY_PATH ) ;
202+ } else if ( this . password !== undefined ) {
203+ command . push ( "--pwd" , this . password ) ;
204+ }
205+ }
206+
207+ if ( this . oauthEnabled ) {
208+ command . push ( "--oauth" , "basic" ) ;
209+ }
210+
130211 this . withCommand ( command ) . withExposedPorts ( this . blobPort , this . queuePort , this . tablePort ) ;
131212
132213 if ( this . accountName !== DEFAULT_ACCOUNT_NAME || this . accountKey !== DEFAULT_ACCOUNT_KEY ) {
@@ -135,6 +216,7 @@ export class AzuriteContainer extends GenericContainer {
135216 } ) ;
136217 }
137218
219+ const protocol : Protocol = this . cert === undefined ? "http" : "https" ;
138220 const startedContainer = await super . start ( ) ;
139221
140222 return new StartedAzuriteContainer (
@@ -143,7 +225,8 @@ export class AzuriteContainer extends GenericContainer {
143225 this . accountKey ,
144226 this . blobPort ,
145227 this . queuePort ,
146- this . tablePort
228+ this . tablePort ,
229+ protocol
147230 ) ;
148231 }
149232}
@@ -155,7 +238,8 @@ export class StartedAzuriteContainer extends AbstractStartedContainer {
155238 private readonly accountKey : string ,
156239 private readonly blobPort : PortWithOptionalBinding ,
157240 private readonly queuePort : PortWithOptionalBinding ,
158- private readonly tablePort : PortWithOptionalBinding
241+ private readonly tablePort : PortWithOptionalBinding ,
242+ private readonly protocol : Protocol
159243 ) {
160244 super ( startedTestContainer ) ;
161245 }
@@ -211,13 +295,13 @@ export class StartedAzuriteContainer extends AbstractStartedContainer {
211295 * @returns A connection string in the form of `DefaultEndpointsProtocol=[protocol];AccountName=[accountName];AccountKey=[accountKey];BlobEndpoint=[blobEndpoint];QueueEndpoint=[queueEndpoint];TableEndpoint=[tableEndpoint];`
212296 */
213297 public getConnectionString ( ) : string {
214- return `DefaultEndpointsProtocol=http ;AccountName=${ this . accountName } ;AccountKey=${
298+ return `DefaultEndpointsProtocol=${ this . protocol } ;AccountName=${ this . accountName } ;AccountKey=${
215299 this . accountKey
216300 } ;BlobEndpoint=${ this . getBlobEndpoint ( ) } ;QueueEndpoint=${ this . getQueueEndpoint ( ) } ;TableEndpoint=${ this . getTableEndpoint ( ) } ;`;
217301 }
218302
219303 private getEndpoint ( port : number , containerName : string ) : string {
220- const url = new URL ( `http ://${ this . getHost ( ) } ` ) ;
304+ const url = new URL ( `${ this . protocol } ://${ this . getHost ( ) } ` ) ;
221305 url . port = port . toString ( ) ;
222306 url . pathname = containerName ;
223307 return url . toString ( ) ;
0 commit comments