modethirteen / authforge
一组用于集成行业标准身份验证和授权的组件
dev-main
2021-09-14 03:44 UTC
Requires
- php: ^7.4.0
- ext-dom: *
- ext-gmp: *
- ext-json: *
- ext-libxml: *
- ext-mbstring: *
- ext-openssl: *
- ext-zlib: *
- modethirteen/fluent-cache: dev-main
- modethirteen/hyperplug: dev-main
- modethirteen/miniflex: dev-main
- modethirteen/type-ex: dev-main
- modethirteen/xarray: dev-main
- psr/event-dispatcher: ^1.0.0
- psr/http-message: ^1.0.1
- psr/log: ^1.1.4
- ramsey/uuid: ~4.1.1
- robrichards/xmlseclibs: ~3.1.1
- symfony/event-dispatcher-contracts: ^2.4.0
- web-token/jwt-checker: ~2.2.11
- web-token/jwt-core: ~2.2.11
- web-token/jwt-key-mgmt: ~2.2.11
- web-token/jwt-signature: ~2.2.11
- web-token/jwt-signature-algorithm-ecdsa: ~2.2.11
- web-token/jwt-signature-algorithm-hmac: ~2.2.11
- web-token/jwt-signature-algorithm-rsa: ~2.2.11
Requires (Dev)
- phpstan/phpstan: ~0.12.99
- phpunit/phpunit: ~9.4.4
This package is auto-updated.
Last update: 2024-09-14 10:22:26 UTC
README
一组用于集成行业标准身份验证和授权的PHP组件
- PHP 7.4 (主要,2.x)
安装
使用 Composer。有两种方法可以将此库添加到您的项目中。
从Composer CLI
./composer.phar require modethirteen/authforge
或在您的项目的composer.json中添加modethirteen/authforge
{ "require": { "modethirteen/authforge": "dev-main" } }
dev-main
是主要开发分支。如果您在生产环境中使用此库,建议您使用稳定版本。
假设您已设置Composer的自动加载器,库可以在 modethirteen\AuthForge\
命名空间中找到。
鸣谢
此存储库中的一些组件,特别是SAML SSO消息的签名、加密和验证,是基于在 OneLogin SAML PHP Toolkit 中找到的库重新设计的。这些组件已经被重构,并且将继续重构,以实现灵活性和平台无关性,符合 PSR兼容性 编程。
入门
虽然可以在应用程序中使用AuthForge组件和库,但向您的应用程序添加SSO服务提供者功能的最快方法是使用 AuthFlowServiceInterface
。
OAuth 2.0 / OpenID Connect 服务提供者(依赖方)
// the application is responsible for providing a concrete OAuth service provider configuration // ...settings can come from anywhere: a file on disk, hardcoded strings, etc. $oauth = new class implements OAuthConfigurationInterface { ... }; // ContextLoggerInterface is an extension of the PSR-3 LoggerInterface (https://www.php-fig.org/psr/psr-3/) $logger = new class implements ContextLoggerInterface { ... }; // DateTimeInterface represents a consistent time of the authentication request or response // ...this time will be used anywhere in the service where dates are outputted or timespans are checked $dateTime = new DateTimeImmutable(); // a PSR-14 EventDispatcher is provided with a post-processing event from OAuthFlowService, so that the application can process identity token claims and natively sign-in or reject the authentication attempt $eventDispatcher = new class implements EventDispatcherInterface { ... } // a UUIDv4 generator for state tokens $uuidFactory = new UuidFactory(); // MutableXArray (https://github.com/modethirteen/XArray) is a helper for writing data to an array data structure // ...it is assumed that $_SESSION is provided to this object so proper state management can occur in OAuthFlowService $session = new MutableXArray($_SESSION); // a OAuthMiddlewareServiceInterface is responsible for handling any followup tasks with an OAuth 2.0 access token, such as, in the case of OpenID Connect, parse the identity token with the identity provider's JWKS, or fetch additional claims from an OpenID Connect UserInfo endpoint. // ...time to configure our OAuthFlowService for OpenID Connect $oidc = new class implements OpenIdConnectConfigurationInterface { ... } // JWKS caching leverages a PSR-16 CacheInterface (https://www.php-fig.org/psr/psr-16/) to store remotely fetched identity token signing keys $cache = new class implements CacheInterface { ... } $caching = new JsonWebKeySetCaching($cache, function(XUri $jsonWebKeysUri) : string { // what cache key should be used to store JWKS in the cache? the configured remote URL is provided so the decision making is left to the application return 'key'; }); // ...create the OpenIdConnectMiddlewareService and include it in the OAuthFlowService $middlewareService = new OpenIdConnectMiddlewareService($oauth, $oidc, $dateTime, $caching, $logger); $service = new OAuthFlowService($oauth, $dateTime, $logger, $middlewareService, $eventDispatcher, $uuidFactory, $session); // ...a NoopOauthMiddlewareService provides plain OAuth 2.0 with no followup tasks (just returns an OAuth 2.0 access token) $middlewareService = new NoopOAuthMiddlewareService(); // the URI to return the user to after the sign-in flow is completed $returnUri = XUri::newFromString('https://app.example.com/dashboard'); // ...back to OpenID Connect, time to kick-off an authorization code flow-based sign-in request to the identity provider and receive a URI to redirect the user to $loginUri = $service->getLoginUri($returnUri); // handle the redirect as the application sees fit header("Location: {$loginUri->toString()}");
HTTP 302 https://idp.example.com/authorize?client_id={client_id}&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcode&response_type=code&state={state}&scope=openid
// the application will handle request routing when the identity provider redirects the user back with an authorization code // ...provide a PSR-7 ServiceRequestInterface and AuthForge will process the code, dispatch an post-processing event, and return the original application return URI $request = new ServerRequestEx(new class implements ServerRequestInterface { ... }, function(ServerRequestInterface $req) { // PSR-7 messages are not strictly opinionated on the return type for the body (object|array|null) // ...AuthForge requires an array-type, therefore this callback needs to convert whatever the application HTTP message body type is to array }); $returnUri = $service->getAuthenticatedUri($request); // ...meanwhile what does the event dispatcher send off to its listeners? $eventDispatcher->addListener(OAuthFlowEvent::class, function(object $event) : void { // time the service started processing the authorization code $event->getDateTime(); // a collection of identity token claims $event->getClaims(); // the OAuth middleware service that handled the flow (ex: OpenIdConnectMiddlewareService) $event->getMiddlewareServiceName(); // the raw HTTP response from requesting an access token from the identity provider $event->getTokenResult(); }); // the application should now have everything it needs to sign in the user (or not!)
SAML SSO 服务提供者
// the application is responsible for providing a concrete SAML SSO service provider configuration // ...settings can come from anywhere: a file on disk, hardcoded strings, etc. $oauth = new class implements SamlConfigurationInterface { ... }; // ContextLoggerInterface is an extension of the PSR-3 LoggerInterface (https://www.php-fig.org/psr/psr-3/) $logger = new class implements ContextLoggerInterface { ... }; // DateTimeInterface represents a consistent time of the authentication request or response // ...this time will be used anywhere in the service where dates are outputted or timespans are checked $dateTime = new DateTimeImmutable(); // a PSR-14 EventDispatcher is provided with a post-processing event from SamlFlowService, so that the application can process identity token claims and natively sign-in or reject the authentication attempt $eventDispatcher = new class implements EventDispatcherInterface { ... } // a UUIDv4 generator for request IDs $uuidFactory = new UuidFactory(); // the session index registry stores identity provider session indexes in whatever manner the application sees fit // ...these session indexes are necessary to handle both SAML Single Logout service provider and identity provider initiated requests $sessionIndexRegistry = new class implements SessionIndexRegistryInterface { ... } // the document factory can parse, sign, and encrypt SAML $documentFactory = new DocumentFactory(new class implements DocumentSchemaResolverInterface { /** * @param string $schema * @return string - a fully qualified OS path to the requested XSD file */ public function resolve(string $schema) : string { // the SAML 2.0 schema definition files are located in this repository/package under /redist/OneLogin/schemas (thanks OneLogin!) // ...it's the responsibility of your application to correctly resolve a filesystem path to this directory } }); // ...time to create the SamlFlowService $service = new SamlFlowService($saml, $dateTime, $logger, $uuidFactory, $eventDispatcher, $documentFactory, $sessionIndexRegistry); // the URI to return the user to after the sign-in flow is completed $returnUri = XUri::newFromString('https://app.example.com/dashboard'); // generate an AuthnRequest to the identity provider and get a URI to redirect the user to $loginUri = $service->getLoginUri($returnUri); // handle the redirect as the application sees fit header("Location: {$loginUri->toString()}");
HTTP 302 https://idp.example.com/saml?SAMLRequest={request}&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1&Signature={signature}
// the application will handle request routing when the identity provider redirects the user back with an AuthnResponse // ...provide a PSR-7 ServiceRequestInterface and AuthForge will process the response, dispatch an post-processing event, and return the original application return URI $request = new ServerRequestEx(new class implements ServerRequestInterface { ... }, function(ServerRequestInterface $req) { // PSR-7 messages are not strictly opinionated on the return type for the body (object|array|null) // ...AuthForge requires an array-type, therefore this callback needs to convert whatever the application HTTP message body type is to array }); $returnUri = $service->getAuthenticatedUri($request); // ...meanwhile what does the event dispatcher send off to its listeners? $eventDispatcher->addListener(SamlFlowEvent::class, function(object $event) : void { // time the service started processing the AuthnResponse $event->getDateTime(); // a collection of assertion attribute claims $event->getClaims(); // the identity provider session index $event->getSessionIndex(); }); // the application should now have everything it needs to sign in the user (or not!)