Skip to content

Commit 6e36411

Browse files
rhuanbarretoRhuandplewisdavimacedo
authored
Keycloak auth adapter (#6376)
* Copy auth adapter to create keycloak adapter * Add keycloak authentication adapter * Add keycloak to auth adapter tests * Improve tests Co-authored-by: Rhuan <[email protected]> Co-authored-by: Diamond Lewis <[email protected]> Co-authored-by: Antonio Davi Macedo Coelho de Castro <[email protected]>
1 parent 4245a8f commit 6e36411

File tree

3 files changed

+384
-1
lines changed

3 files changed

+384
-1
lines changed

spec/AuthenticationAdapters.spec.js

Lines changed: 251 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ describe('AuthenticationProviders', function () {
4141
'weibo',
4242
'phantauth',
4343
'microsoft',
44+
'keycloak',
4445
].map(function (providerName) {
4546
it('Should validate structure of ' + providerName, done => {
4647
const provider = require('../lib/Adapters/Auth/' + providerName);
@@ -65,7 +66,7 @@ describe('AuthenticationProviders', function () {
6566
});
6667

6768
it(`should provide the right responses for adapter ${providerName}`, async () => {
68-
const noResponse = ['twitter', 'apple', 'gcenter', 'google'];
69+
const noResponse = ['twitter', 'apple', 'gcenter', "google", 'keycloak'];
6970
if (noResponse.includes(providerName)) {
7071
return;
7172
}
@@ -703,6 +704,255 @@ describe('google play games service auth', () => {
703704
});
704705
});
705706

707+
describe('keycloak auth adapter', () => {
708+
const keycloak = require('../lib/Adapters/Auth/keycloak');
709+
const httpsRequest = require('../lib/Adapters/Auth/httpsRequest');
710+
711+
it('validateAuthData should fail without access token', async () => {
712+
const authData = {
713+
id: 'fakeid',
714+
};
715+
try {
716+
await keycloak.validateAuthData(authData);
717+
fail();
718+
} catch (e) {
719+
expect(e.message).toBe('Missing access token and/or User id');
720+
}
721+
});
722+
723+
it('validateAuthData should fail without user id', async () => {
724+
const authData = {
725+
access_token: 'sometoken',
726+
};
727+
try {
728+
await keycloak.validateAuthData(authData);
729+
fail();
730+
} catch (e) {
731+
expect(e.message).toBe('Missing access token and/or User id');
732+
}
733+
});
734+
735+
it('validateAuthData should fail without config', async () => {
736+
const options = {
737+
keycloak: {
738+
config: null,
739+
},
740+
};
741+
const authData = {
742+
id: 'fakeid',
743+
access_token: 'sometoken',
744+
};
745+
const { adapter, providerOptions } = authenticationLoader.loadAuthAdapter(
746+
'keycloak',
747+
options
748+
);
749+
try {
750+
await adapter.validateAuthData(authData, providerOptions);
751+
fail();
752+
} catch (e) {
753+
expect(e.message).toBe('Missing keycloak configuration');
754+
}
755+
});
756+
757+
it('validateAuthData should fail connect error', async () => {
758+
spyOn(httpsRequest, 'get').and.callFake(() => {
759+
return Promise.reject({
760+
text: JSON.stringify({ error: 'hosting_error' }),
761+
});
762+
});
763+
const options = {
764+
keycloak: {
765+
config: {
766+
'auth-server-url': 'http://example.com',
767+
realm: 'new',
768+
},
769+
},
770+
};
771+
const authData = {
772+
id: 'fakeid',
773+
access_token: 'sometoken',
774+
};
775+
const { adapter, providerOptions } = authenticationLoader.loadAuthAdapter(
776+
'keycloak',
777+
options
778+
);
779+
try {
780+
await adapter.validateAuthData(authData, providerOptions);
781+
fail();
782+
} catch (e) {
783+
expect(e.message).toBe('Could not connect to the authentication server');
784+
}
785+
});
786+
787+
it('validateAuthData should fail with error description', async () => {
788+
spyOn(httpsRequest, 'get').and.callFake(() => {
789+
return Promise.reject({
790+
text: JSON.stringify({ error_description: 'custom error message' }),
791+
});
792+
});
793+
const options = {
794+
keycloak: {
795+
config: {
796+
'auth-server-url': 'http://example.com',
797+
realm: 'new',
798+
},
799+
},
800+
};
801+
const authData = {
802+
id: 'fakeid',
803+
access_token: 'sometoken',
804+
};
805+
const { adapter, providerOptions } = authenticationLoader.loadAuthAdapter(
806+
'keycloak',
807+
options
808+
);
809+
try {
810+
await adapter.validateAuthData(authData, providerOptions);
811+
fail();
812+
} catch (e) {
813+
expect(e.message).toBe('custom error message');
814+
}
815+
});
816+
817+
it('validateAuthData should fail with invalid auth', async () => {
818+
spyOn(httpsRequest, 'get').and.callFake(() => {
819+
return Promise.resolve({});
820+
});
821+
const options = {
822+
keycloak: {
823+
config: {
824+
'auth-server-url': 'http://example.com',
825+
realm: 'new',
826+
},
827+
},
828+
};
829+
const authData = {
830+
id: 'fakeid',
831+
access_token: 'sometoken',
832+
};
833+
const { adapter, providerOptions } = authenticationLoader.loadAuthAdapter(
834+
'keycloak',
835+
options
836+
);
837+
try {
838+
await adapter.validateAuthData(authData, providerOptions);
839+
fail();
840+
} catch (e) {
841+
expect(e.message).toBe('Invalid authentication');
842+
}
843+
});
844+
845+
it('validateAuthData should fail with invalid groups', async () => {
846+
spyOn(httpsRequest, 'get').and.callFake(() => {
847+
return Promise.resolve({
848+
data: {
849+
sub: 'fakeid',
850+
roles: ['role1'],
851+
groups: ['unknown'],
852+
},
853+
});
854+
});
855+
const options = {
856+
keycloak: {
857+
config: {
858+
'auth-server-url': 'http://example.com',
859+
realm: 'new',
860+
},
861+
},
862+
};
863+
const authData = {
864+
id: 'fakeid',
865+
access_token: 'sometoken',
866+
roles: ['role1'],
867+
groups: ['group1'],
868+
};
869+
const { adapter, providerOptions } = authenticationLoader.loadAuthAdapter(
870+
'keycloak',
871+
options
872+
);
873+
try {
874+
await adapter.validateAuthData(authData, providerOptions);
875+
fail();
876+
} catch (e) {
877+
expect(e.message).toBe('Invalid authentication');
878+
}
879+
});
880+
881+
it('validateAuthData should fail with invalid roles', async () => {
882+
spyOn(httpsRequest, 'get').and.callFake(() => {
883+
return Promise.resolve({
884+
data: {
885+
sub: 'fakeid',
886+
roles: 'unknown',
887+
groups: ['group1'],
888+
},
889+
});
890+
});
891+
const options = {
892+
keycloak: {
893+
config: {
894+
'auth-server-url': 'http://example.com',
895+
realm: 'new',
896+
},
897+
},
898+
};
899+
const authData = {
900+
id: 'fakeid',
901+
access_token: 'sometoken',
902+
roles: ['role1'],
903+
groups: ['group1'],
904+
};
905+
const { adapter, providerOptions } = authenticationLoader.loadAuthAdapter(
906+
'keycloak',
907+
options
908+
);
909+
try {
910+
await adapter.validateAuthData(authData, providerOptions);
911+
fail();
912+
} catch (e) {
913+
expect(e.message).toBe('Invalid authentication');
914+
}
915+
});
916+
917+
it('validateAuthData should handle authentication', async () => {
918+
spyOn(httpsRequest, 'get').and.callFake(() => {
919+
return Promise.resolve({
920+
data: {
921+
sub: 'fakeid',
922+
roles: ['role1'],
923+
groups: ['group1'],
924+
},
925+
});
926+
});
927+
const options = {
928+
keycloak: {
929+
config: {
930+
'auth-server-url': 'http://example.com',
931+
realm: 'new',
932+
},
933+
},
934+
};
935+
const authData = {
936+
id: 'fakeid',
937+
access_token: 'sometoken',
938+
roles: ['role1'],
939+
groups: ['group1'],
940+
};
941+
const { adapter, providerOptions } = authenticationLoader.loadAuthAdapter(
942+
'keycloak',
943+
options
944+
);
945+
await adapter.validateAuthData(authData, providerOptions);
946+
expect(httpsRequest.get).toHaveBeenCalledWith({
947+
host: 'http://example.com',
948+
path: '/realms/new/protocol/openid-connect/userinfo',
949+
headers: {
950+
Authorization: 'Bearer sometoken',
951+
},
952+
});
953+
});
954+
});
955+
706956
describe('oauth2 auth adapter', () => {
707957
const oauth2 = require('../lib/Adapters/Auth/oauth2');
708958
const httpsRequest = require('../lib/Adapters/Auth/httpsRequest');

src/Adapters/Auth/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const weibo = require('./weibo');
2222
const oauth2 = require('./oauth2');
2323
const phantauth = require('./phantauth');
2424
const microsoft = require('./microsoft');
25+
const keycloak = require('./keycloak');
2526
const ldap = require('./ldap');
2627

2728
const anonymous = {
@@ -56,6 +57,7 @@ const providers = {
5657
weibo,
5758
phantauth,
5859
microsoft,
60+
keycloak,
5961
ldap,
6062
};
6163

0 commit comments

Comments
 (0)