11'use strict' ;
22
3+ var async = require ( 'async' ) ;
34var path = require ( 'path' ) ;
45var stormpath = require ( 'stormpath' ) ;
56var stormpathConfig = require ( 'stormpath-config' ) ;
7+ var uuid = require ( 'uuid' ) ;
68var configStrategy = stormpathConfig . strategy ;
79
10+ function DefaultJwksCacheManager ( defaultJwksCacheManagerConfig ) {
11+ defaultJwksCacheManagerConfig = defaultJwksCacheManagerConfig || { } ;
12+ this . ttl = defaultJwksCacheManagerConfig . ttl ;
13+ this . jwks = null ;
14+ }
15+ DefaultJwksCacheManager . prototype . getJwks = function getJwks ( ) {
16+ var now = new Date ( ) . getTime ( ) ;
17+ if ( now > ( this . lastSet + this . ttl ) ) {
18+ this . jwks = null ;
19+ }
20+
21+ return this . jwks ;
22+ } ;
23+ DefaultJwksCacheManager . prototype . setJwks = function setJwks ( jwks ) {
24+ this . lastSet = new Date ( ) . getTime ( ) ;
25+ this . jwks = jwks ;
26+ } ;
27+
28+
829// Factory method to create a client using a configuration only.
930// The configuration provided to this factory is the final configuration.
1031function ClientFactory ( config ) {
@@ -14,15 +35,117 @@ function ClientFactory(config) {
1435 ] )
1536 ) ;
1637}
38+ /**
39+ * Fetches authorization server and client configuration from Okta, requires
40+ * an already defined okta.org and okta.applicationId
41+ */
42+ function OktaConfigurationStrategy ( ) {
43+
44+ }
45+ OktaConfigurationStrategy . prototype . process = function process ( config , callback ) {
46+ var client = new ClientFactory ( config ) ;
47+ var applicationCredentialsResourceUrl = '/internal/apps/' + config . application . id + '/settings/clientcreds' ;
48+
49+ async . parallel ( {
50+ applicationResource : client . getApplication . bind ( client , '/apps/' + config . application . id ) ,
51+ applicationCredentialsResource : client . getResource . bind ( client , applicationCredentialsResourceUrl ) ,
52+ idps : client . getResource . bind ( client , '/idps' )
53+ } , function ( err , results ) {
54+
55+ if ( err ) {
56+ return callback ( err ) ;
57+ }
58+
59+ /**
60+ * Copy the authorization server ID to it's new location on the applicatin's profile object.
61+ */
62+
63+ var authServerIdAtOldLocation = results . applicationResource . settings . notifications . vpn . message ;
64+ var authServerIdAtNewLocation = results . applicationResource . profile && results . applicationResource . profile . forAuthorizationServerId ;
65+
66+ config . authorizationServerId = authServerIdAtNewLocation || authServerIdAtOldLocation ;
67+
68+ if ( ! authServerIdAtNewLocation ) {
69+ if ( ! results . applicationResource . profile ) {
70+ results . applicationResource . profile = { } ;
71+ }
72+ results . applicationResource . profile . forAuthorizationServerId = authServerIdAtOldLocation ;
73+ results . applicationResource . save ( function ( err ) {
74+ if ( err ) {
75+ console . error ( err ) ; // eslint-disable-line no-console
76+ }
77+ console . log ( 'Persisted authorization server ID to new location on application.settings' ) ; // eslint-disable-line no-console
78+ } ) ;
79+ }
80+
81+ config . authorizationServerClientId = results . applicationCredentialsResource . client_id ;
82+ config . authorizationServerClientSecret = results . applicationCredentialsResource . client_secret ;
83+
84+ var idps = results . idps . items . filter ( function ( idp ) {
85+ return [ 'LINKEDIN' , 'FACEBOOK' , 'GOOGLE' ] . indexOf ( idp . type ) > - 1 ;
86+ } ) ;
87+
88+ var idpConfiguration = idps . reduce ( function ( idpConfiguration , idp ) {
89+ var providerId = idp . type . toLowerCase ( ) ;
90+ var providedConfig = config . web . social [ providerId ] || { } ;
91+
92+ var clientId = idp . protocol . credentials . client . client_id ;
93+
94+ var redirectUri = '/callbacks/' + providerId ;
95+
96+ var scope = providedConfig . scope || idp . protocol . scopes . join ( ' ' ) ;
97+
98+ var authorizeUriParams = {
99+ client_id : config . authorizationServerClientId ,
100+ idp : idp . id ,
101+ response_type : 'code' ,
102+ response_mode : 'query' ,
103+ scope : scope ,
104+ redirect_uri : '{redirectUri}' , // Leave this here for now, will be replaced when a view is requested
105+ nonce : uuid . v4 ( ) ,
106+ state : '{state}' // Leave this here for now, will be replaced when a view is requested
107+ } ;
108+
109+ var authorizeUri = config . org + 'oauth2/' + config . authorizationServerId + '/v1/authorize?' ;
110+
111+ authorizeUri += Object . keys ( authorizeUriParams ) . reduce ( function ( queryString , param ) {
112+ return queryString += '&' + param + '=' + authorizeUriParams [ param ] ;
113+ } , '' ) ;
114+
115+ idpConfiguration [ providerId ] = {
116+ clientId : clientId ,
117+ clientSecret : idp . protocol . credentials . client . client_secret ,
118+ enabled : idp . status === 'ACTIVE' ,
119+ providerId : providerId ,
120+ providerType : providerId ,
121+ scope : scope ,
122+ uri : redirectUri , // for back compat if custom templates are dep
123+ redirectUri : redirectUri ,
124+ authorizeUri : authorizeUri
125+ } ;
126+
127+ return idpConfiguration ;
128+ } , { } ) ;
129+
130+ config . web . social = idpConfiguration ;
131+
132+ if ( config . web . refreshTokenCookie . maxAge ) {
133+ config . web . refreshTokenCookie . maxAge = parseInt ( config . web . refreshTokenCookie . maxAge , 10 ) ;
134+ }
135+
136+ config . jwksCacheManager = config . jwksCacheManager || new DefaultJwksCacheManager ( config . web . defaultJwksCacheManagerConfig ) ;
137+
138+ callback ( null , config ) ;
139+
140+ } ) ;
141+ } ;
17142
18143module . exports = function ( config ) {
19144 var configLoader = stormpath . configLoader ( config ) ;
20145
21146 // Load our integration config.
22147 configLoader . prepend ( new configStrategy . LoadFileConfigStrategy ( path . join ( __dirname , '/config.yml' ) , true ) ) ;
23- configLoader . add ( new configStrategy . EnrichIntegrationConfigStrategy ( config ) ) ;
24- configLoader . add ( new configStrategy . EnrichClientFromRemoteConfigStrategy ( ClientFactory ) ) ;
25- configLoader . add ( new configStrategy . EnrichIntegrationFromRemoteConfigStrategy ( ClientFactory ) ) ;
148+ configLoader . add ( new OktaConfigurationStrategy ( ClientFactory ) ) ;
26149
27150 return new stormpath . Client ( configLoader ) ;
28- } ;
151+ } ;
0 commit comments