forked from winteragency/feathers-saml
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The catch blocks have some "new" syntax we need to adhere to: microsoft/TypeScript#36775 As of Feathers 4, the request and response body are actually of type any, but we have to specify that explicitly. We can probably get rid of this `// @ts-ignore` now.
- Loading branch information
Showing
1 changed file
with
128 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,168 +1,195 @@ | ||
// @ts-ignore | ||
import Debug from 'debug'; | ||
import { Application } from '@feathersjs/feathers'; | ||
import { AuthenticationResult } from '@feathersjs/authentication'; | ||
import Debug from 'debug' | ||
import { Application } from '@feathersjs/feathers' | ||
import { AuthenticationResult } from '@feathersjs/authentication' | ||
import { | ||
Application as ExpressApplication, | ||
original as express | ||
} from '@feathersjs/express'; | ||
import { SamlSetupSettings } from './utils'; | ||
import { SamlStrategy } from './strategy'; | ||
import { BadRequest } from '@feathersjs/errors'; | ||
const debug = Debug('feathers-saml/express'); | ||
} from '@feathersjs/express' | ||
import { SamlSetupSettings } from './utils' | ||
import { SamlStrategy } from './strategy' | ||
import { BadRequest } from '@feathersjs/errors' | ||
|
||
const debug = Debug('feathers-saml/express') | ||
|
||
export default (options: SamlSetupSettings) => { | ||
return (feathersApp: Application) => { | ||
const { authService } = options; | ||
const app = feathersApp as ExpressApplication; | ||
const config = app.get(authService + 'Saml'); | ||
const { authService } = options | ||
const app = feathersApp as ExpressApplication | ||
const config = app.get(authService + 'Saml') | ||
|
||
if (!config) { | ||
debug('No SAML configuration found, skipping Express SAML setup'); | ||
return; | ||
debug('No SAML configuration found, skipping Express SAML setup') | ||
return | ||
} | ||
|
||
if (!config.sp) { | ||
debug('No SAML SP found, skipping Express SAML setup'); | ||
return; | ||
debug('No SAML SP found, skipping Express SAML setup') | ||
return | ||
} | ||
|
||
if (!config.idp) { | ||
debug('No SAML IdP found, skipping Express SAML setup'); | ||
return; | ||
debug('No SAML IdP found, skipping Express SAML setup') | ||
return | ||
} | ||
|
||
const { sp, idp, path } = config; | ||
const { sp, idp, path } = config | ||
|
||
const authApp = express() | ||
|
||
const authApp = express(); | ||
|
||
authApp.get('/', async (req, res) => { | ||
sp.create_login_request_url(idp, config.loginRequestOptions ? config.loginRequestOptions : {}, async (err: Error, login_url: string, request_id: string) => { | ||
if (err != null) { | ||
return res.send(500); | ||
} | ||
authApp.get('/', async (req: any, res: any) => { | ||
sp.create_login_request_url( | ||
idp, | ||
config.loginRequestOptions ? config.loginRequestOptions : {}, | ||
async (err: Error, login_url: string, request_id: string) => { | ||
if (err != null) { | ||
return res.send(500) | ||
} | ||
|
||
res.redirect(login_url); | ||
}); | ||
}); | ||
res.redirect(login_url) | ||
} | ||
) | ||
}) | ||
|
||
authApp.get('/metadata.xml', async (req, res) => { | ||
res.type('application/xml'); | ||
res.send(sp.create_metadata()); | ||
}); | ||
authApp.get('/metadata.xml', async (req: any, res: any) => { | ||
res.type('application/xml') | ||
res.send(sp.create_metadata()) | ||
}) | ||
|
||
authApp.post('/assert', async (req, res, next) => { | ||
const service = app.defaultAuthentication(authService); | ||
const [ strategy ] = service.getStrategies('saml') as SamlStrategy[]; | ||
authApp.post('/assert', async (req: any, res: any, next: any) => { | ||
const service = app.defaultAuthentication(authService) | ||
const [strategy] = service.getStrategies('saml') as SamlStrategy[] | ||
const params: any = { | ||
authStrategies: [ strategy.name ] | ||
}; | ||
const sendResponse = async (data: AuthenticationResult|Error) => { | ||
authStrategies: [strategy.name] | ||
} | ||
const sendResponse = async (data: AuthenticationResult | Error) => { | ||
try { | ||
const redirect = await strategy.getRedirect(data, params); | ||
const redirect = await strategy.getRedirect(data, params) | ||
|
||
if (redirect !== null) { | ||
res.redirect(redirect); | ||
res.redirect(redirect) | ||
} else if (data instanceof Error) { | ||
throw data; | ||
throw data | ||
} else { | ||
res.json(data); | ||
res.json(data) | ||
} | ||
} catch (error) { | ||
debug('SAML error', error); | ||
next(error); | ||
debug('SAML error', error) | ||
next(error) | ||
} | ||
}; | ||
} | ||
|
||
try { | ||
const samlResponse: any = await new Promise((resolve, reject) => { | ||
let loginResponseOptions: any = {}; | ||
let loginResponseOptions: any = {} | ||
|
||
if (config.loginResponseOptions) { | ||
loginResponseOptions = config.loginResponseOptions; | ||
loginResponseOptions = config.loginResponseOptions | ||
} | ||
|
||
loginResponseOptions.request_body = req.body; | ||
|
||
sp.post_assert(idp, loginResponseOptions, async (err: Error, saml_response: any) => { | ||
if (err != null) { | ||
reject(err); | ||
return; | ||
|
||
loginResponseOptions.request_body = req.body | ||
|
||
sp.post_assert( | ||
idp, | ||
loginResponseOptions, | ||
async (err: Error, saml_response: any) => { | ||
if (err != null) { | ||
reject(err) | ||
return | ||
} | ||
|
||
resolve(saml_response) | ||
} | ||
|
||
resolve(saml_response); | ||
}); | ||
}); | ||
) | ||
}) | ||
|
||
const authentication = { | ||
strategy: strategy.name, | ||
...samlResponse | ||
}; | ||
} | ||
|
||
params.payload = { | ||
nameId: samlResponse && samlResponse.user && samlResponse.user.name_id ? samlResponse.user.name_id : null, | ||
sessionIndex: samlResponse && samlResponse.user && samlResponse.user.session_index ? samlResponse.user.session_index : null, | ||
nameId: | ||
samlResponse && samlResponse.user && samlResponse.user.name_id | ||
? samlResponse.user.name_id | ||
: null, | ||
sessionIndex: | ||
samlResponse && samlResponse.user && samlResponse.user.session_index | ||
? samlResponse.user.session_index | ||
: null, | ||
samlToken: true | ||
}; | ||
debug(`Calling ${authService}.create authentication with SAML strategy`); | ||
} | ||
|
||
debug(`Calling ${authService}.create authentication with SAML strategy`) | ||
|
||
if (config.samlTokenExpiry) { | ||
params.jwtOptions = { | ||
expiresIn: config.samlTokenExpiry | ||
}; | ||
} | ||
} | ||
|
||
const authResult = await service.create(authentication, params); | ||
const authResult = await service.create(authentication, params) | ||
|
||
debug('Successful SAML authentication, sending response'); | ||
debug('Successful SAML authentication, sending response') | ||
|
||
await sendResponse(authResult); | ||
await sendResponse(authResult) | ||
} catch (error) { | ||
debug('Received SAML authentication error', error.stack); | ||
await sendResponse(error); | ||
if (error instanceof Error) { | ||
debug('Received SAML authentication error', error.stack) | ||
await sendResponse(error) | ||
} | ||
} | ||
}); | ||
}) | ||
|
||
authApp.get('/logout', async (req, res, next) => { | ||
const { nameId, sessionIndex } = req.query; | ||
authApp.get('/logout', async (req: any, res: any, next: any) => { | ||
const { nameId, sessionIndex } = req.query | ||
|
||
if (!nameId || !sessionIndex) { | ||
return next(new BadRequest('`nameId` and `sessionIndex` must be set in query params')); | ||
return next( | ||
new BadRequest( | ||
'`nameId` and `sessionIndex` must be set in query params' | ||
) | ||
) | ||
} | ||
let logoutRequestOptions: any = {}; | ||
|
||
let logoutRequestOptions: any = {} | ||
|
||
if (config.logoutRequestOptions) { | ||
logoutRequestOptions = config.logoutRequestOptions; | ||
logoutRequestOptions = config.logoutRequestOptions | ||
} | ||
|
||
logoutRequestOptions.name_id = nameId; | ||
logoutRequestOptions.session_ndex = sessionIndex; | ||
|
||
sp.create_logout_request_url(idp, logoutRequestOptions, async (err: Error, logout_url: string) => { | ||
if (err != null) { | ||
next(err); | ||
return; | ||
} | ||
logoutRequestOptions.name_id = nameId | ||
logoutRequestOptions.session_ndex = sessionIndex | ||
|
||
res.redirect(logout_url); | ||
}); | ||
}); | ||
sp.create_logout_request_url( | ||
idp, | ||
logoutRequestOptions, | ||
async (err: Error, logout_url: string) => { | ||
if (err != null) { | ||
next(err) | ||
return | ||
} | ||
|
||
authApp.get('/slo', async (req, res, next) => { | ||
sp.create_logout_response_url(idp, config.logoutResponseOptions ? config.logoutResponseOptions : {}, async (err: Error, request_url: string) => { | ||
if (err != null) { | ||
next(err); | ||
return; | ||
res.redirect(logout_url) | ||
} | ||
) | ||
}) | ||
|
||
authApp.get('/slo', async (req: any, res: any, next: any) => { | ||
sp.create_logout_response_url( | ||
idp, | ||
config.logoutResponseOptions ? config.logoutResponseOptions : {}, | ||
async (err: Error, request_url: string) => { | ||
if (err != null) { | ||
next(err) | ||
return | ||
} | ||
|
||
res.redirect(request_url); | ||
}); | ||
}); | ||
|
||
res.redirect(request_url) | ||
} | ||
) | ||
}) | ||
|
||
app.use(path, authApp); | ||
}; | ||
}; | ||
app.use(path, authApp) | ||
} | ||
} |