Skip to content

Commit 8c5d2e2

Browse files
authored
Merge pull request #701 from brendandburns/auth
Add expiration property for Azure and a unit test.
2 parents 6626ff0 + 18dd878 commit 8c5d2e2

File tree

2 files changed

+287
-3
lines changed

2 files changed

+287
-3
lines changed

src/azure_auth.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ Currently user.authProvider has `any` type and so we don't have a type for user.
1111
We therefore define its type here
1212
*/
1313
interface Config {
14-
expiry: string;
14+
expiry?: string;
1515
['cmd-args']?: string;
1616
['cmd-path']?: string;
1717
['token-key']: string;
1818
['expiry-key']: string;
1919
['access-token']?: string;
20+
['expires-on']?: string;
2021
}
2122
export class AzureAuth implements Authenticator {
2223
public isAuthProvider(user: User): boolean {
@@ -47,14 +48,16 @@ export class AzureAuth implements Authenticator {
4748
private isExpired(config: Config): boolean {
4849
const token = config['access-token'];
4950
const expiry = config.expiry;
51+
const expiresOn = config['expires-on'];
52+
5053
if (!token) {
5154
return true;
5255
}
53-
if (!expiry) {
56+
if (!expiry && !expiresOn) {
5457
return false;
5558
}
5659

57-
const expiration = Date.parse(expiry);
60+
const expiration = expiry ? Date.parse(expiry) : new Date(parseInt(expiresOn!, 10));
5861
if (expiration < Date.now()) {
5962
return true;
6063
}

src/config_test.ts

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,287 @@ describe('KubeConfig', () => {
616616
expect(opts.headers.Authorization).to.equal(`Bearer ${token}`);
617617
}
618618
});
619+
it('should populate from auth provider', async () => {
620+
const config = new KubeConfig();
621+
const token = 'token';
622+
config.loadFromClusterAndUser(
623+
{ skipTLSVerify: false } as Cluster,
624+
{
625+
authProvider: {
626+
name: 'azure',
627+
config: {
628+
'access-token': token,
629+
expiry: 'Fri Aug 24 07:32:05 PDT 3018',
630+
},
631+
},
632+
} as User,
633+
);
634+
const opts = {} as requestlib.Options;
635+
636+
await config.applyToRequest(opts);
637+
expect(opts.headers).to.not.be.undefined;
638+
if (opts.headers) {
639+
expect(opts.headers.Authorization).to.equal(`Bearer ${token}`);
640+
}
641+
opts.headers = [];
642+
opts.headers.Host = 'foo.com';
643+
await config.applyToRequest(opts);
644+
expect(opts.headers.Authorization).to.equal(`Bearer ${token}`);
645+
});
646+
647+
it('should populate from auth provider without expirty', async () => {
648+
const config = new KubeConfig();
649+
const token = 'token';
650+
config.loadFromClusterAndUser(
651+
{ skipTLSVerify: false } as Cluster,
652+
{
653+
authProvider: {
654+
name: 'azure',
655+
config: {
656+
'access-token': token,
657+
},
658+
},
659+
} as User,
660+
);
661+
const opts = {} as requestlib.Options;
662+
663+
await config.applyToRequest(opts);
664+
expect(opts.headers).to.not.be.undefined;
665+
if (opts.headers) {
666+
expect(opts.headers.Authorization).to.equal(`Bearer ${token}`);
667+
}
668+
});
669+
670+
it('should populate rejectUnauthorized=false when skipTLSVerify is set', async () => {
671+
const config = new KubeConfig();
672+
const token = 'token';
673+
config.loadFromClusterAndUser(
674+
{ skipTLSVerify: true } as Cluster,
675+
{
676+
authProvider: {
677+
name: 'azure',
678+
config: {
679+
'access-token': token,
680+
},
681+
},
682+
} as User,
683+
);
684+
const opts = {} as requestlib.Options;
685+
686+
await config.applyToRequest(opts);
687+
expect(opts.rejectUnauthorized).to.equal(false);
688+
});
689+
690+
it('should not set rejectUnauthorized if skipTLSVerify is not set', async () => {
691+
// This test is just making 100% sure we validate certs unless we explictly set
692+
// skipTLSVerify = true
693+
const config = new KubeConfig();
694+
const token = 'token';
695+
config.loadFromClusterAndUser(
696+
{} as Cluster,
697+
{
698+
authProvider: {
699+
name: 'azure',
700+
config: {
701+
'access-token': token,
702+
},
703+
},
704+
} as User,
705+
);
706+
const opts = {} as requestlib.Options;
707+
708+
await config.applyToRequest(opts);
709+
expect(opts.rejectUnauthorized).to.equal(undefined);
710+
});
711+
712+
it('should throw with expired token and no cmd', () => {
713+
const config = new KubeConfig();
714+
config.loadFromClusterAndUser(
715+
{ skipTLSVerify: false } as Cluster,
716+
{
717+
authProvider: {
718+
name: 'azure',
719+
config: {
720+
expiry: 'Aug 24 07:32:05 PDT 2017',
721+
},
722+
},
723+
} as User,
724+
);
725+
const opts = {} as requestlib.Options;
726+
727+
return expect(config.applyToRequest(opts)).to.eventually.be.rejectedWith('Token is expired!');
728+
});
729+
730+
it('should throw with bad command', () => {
731+
const config = new KubeConfig();
732+
config.loadFromClusterAndUser(
733+
{ skipTLSVerify: false } as Cluster,
734+
{
735+
authProvider: {
736+
name: 'azure',
737+
config: {
738+
'access-token': 'token',
739+
expiry: 'Aug 24 07:32:05 PDT 2017',
740+
'cmd-path': 'non-existent-command',
741+
},
742+
},
743+
} as User,
744+
);
745+
const opts = {} as requestlib.Options;
746+
return expect(config.applyToRequest(opts)).to.eventually.be.rejectedWith(
747+
/Failed to refresh token/,
748+
);
749+
});
750+
751+
it('should exec with expired token', async () => {
752+
// TODO: fix this test for Windows
753+
if (process.platform === 'win32') {
754+
return;
755+
}
756+
const config = new KubeConfig();
757+
const token = 'token';
758+
const responseStr = `{"token":{"accessToken":"${token}"}}`;
759+
config.loadFromClusterAndUser(
760+
{ skipTLSVerify: false } as Cluster,
761+
{
762+
authProvider: {
763+
name: 'azure',
764+
config: {
765+
expiry: 'Aug 24 07:32:05 PDT 2017',
766+
'cmd-path': 'echo',
767+
'cmd-args': `'${responseStr}'`,
768+
'token-key': '{.token.accessToken}',
769+
'expiry-key': '{.token.token_expiry}',
770+
},
771+
},
772+
} as User,
773+
);
774+
const opts = {} as requestlib.Options;
775+
await config.applyToRequest(opts);
776+
expect(opts.headers).to.not.be.undefined;
777+
if (opts.headers) {
778+
expect(opts.headers.Authorization).to.equal(`Bearer ${token}`);
779+
}
780+
});
781+
782+
it('should exec with expired token', async () => {
783+
// TODO: fix this test for Windows
784+
if (process.platform === 'win32') {
785+
return;
786+
}
787+
const config = new KubeConfig();
788+
const token = 'token';
789+
const responseStr = `{"token":{"accessToken":"${token}"}}`;
790+
config.loadFromClusterAndUser(
791+
{ skipTLSVerify: false } as Cluster,
792+
{
793+
authProvider: {
794+
name: 'azure',
795+
config: {
796+
'expires-on': '1590757517834',
797+
'cmd-path': 'echo',
798+
'cmd-args': `'${responseStr}'`,
799+
'token-key': '{.token.accessToken}',
800+
'expiry-key': '{.token.token_expiry}',
801+
},
802+
},
803+
} as User,
804+
);
805+
const opts = {} as requestlib.Options;
806+
await config.applyToRequest(opts);
807+
expect(opts.headers).to.not.be.undefined;
808+
if (opts.headers) {
809+
expect(opts.headers.Authorization).to.equal(`Bearer ${token}`);
810+
}
811+
});
812+
813+
it('should exec without access-token', async () => {
814+
// TODO: fix this test for Windows
815+
if (process.platform === 'win32') {
816+
return;
817+
}
818+
const config = new KubeConfig();
819+
const token = 'token';
820+
const responseStr = `{"token":{"accessToken":"${token}"}}`;
821+
config.loadFromClusterAndUser(
822+
{ skipTLSVerify: false } as Cluster,
823+
{
824+
authProvider: {
825+
name: 'azure',
826+
config: {
827+
'cmd-path': 'echo',
828+
'cmd-args': `'${responseStr}'`,
829+
'token-key': '{.token.accessToken}',
830+
'expiry-key': '{.token.token_expiry}',
831+
},
832+
},
833+
} as User,
834+
);
835+
const opts = {} as requestlib.Options;
836+
await config.applyToRequest(opts);
837+
expect(opts.headers).to.not.be.undefined;
838+
if (opts.headers) {
839+
expect(opts.headers.Authorization).to.equal(`Bearer ${token}`);
840+
}
841+
});
842+
it('should exec without access-token', async () => {
843+
// TODO: fix this test for Windows
844+
if (process.platform === 'win32') {
845+
return;
846+
}
847+
const config = new KubeConfig();
848+
const token = 'token';
849+
const responseStr = `{"token":{"accessToken":"${token}"}}`;
850+
config.loadFromClusterAndUser(
851+
{ skipTLSVerify: false } as Cluster,
852+
{
853+
authProvider: {
854+
name: 'azure',
855+
config: {
856+
'cmd-path': 'echo',
857+
'cmd-args': `'${responseStr}'`,
858+
'token-key': '{.token.accessToken}',
859+
'expiry-key': '{.token.token_expiry}',
860+
},
861+
},
862+
} as User,
863+
);
864+
const opts = {} as requestlib.Options;
865+
await config.applyToRequest(opts);
866+
expect(opts.headers).to.not.be.undefined;
867+
if (opts.headers) {
868+
expect(opts.headers.Authorization).to.equal(`Bearer ${token}`);
869+
}
870+
});
871+
it('should exec succesfully with spaces in cmd', async () => {
872+
// TODO: fix this test for Windows
873+
if (process.platform === 'win32') {
874+
return;
875+
}
876+
const config = new KubeConfig();
877+
const token = 'token';
878+
const responseStr = `{"token":{"accessToken":"${token}"}}`;
879+
config.loadFromClusterAndUser(
880+
{ skipTLSVerify: false } as Cluster,
881+
{
882+
authProvider: {
883+
name: 'azure', // applies to gcp too as they are both handled by CloudAuth class
884+
config: {
885+
'cmd-path': path.join(__dirname, '..', 'test', 'echo space.js'),
886+
'cmd-args': `'${responseStr}'`,
887+
'token-key': '{.token.accessToken}',
888+
'expiry-key': '{.token.token_expiry}',
889+
},
890+
},
891+
} as User,
892+
);
893+
const opts = {} as requestlib.Options;
894+
await config.applyToRequest(opts);
895+
expect(opts.headers).to.not.be.undefined;
896+
if (opts.headers) {
897+
expect(opts.headers.Authorization).to.equal(`Bearer ${token}`);
898+
}
899+
});
619900
it('should exec with exec auth and env vars', async () => {
620901
// TODO: fix this test for Windows
621902
if (process.platform === 'win32') {

0 commit comments

Comments
 (0)