OAuthProxyAuthenticator.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <?php
  2. namespace AuthBundle\Security;
  3. use Buzz\Listener\BasicAuthListener;
  4. use Symfony\Component\HttpFoundation\Request;
  5. use Symfony\Component\HttpFoundation\Response;
  6. use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
  7. use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
  8. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  9. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  10. use Symfony\Component\Security\Core\User\UserProviderInterface;
  11. use Symfony\Component\Security\Http\Authentication\SimplePreAuthenticatorInterface;
  12. use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
  13. class OAuthProxyAuthenticator implements SimplePreAuthenticatorInterface, AuthenticationFailureHandlerInterface
  14. {
  15. /**
  16. * @var string
  17. */
  18. private $client_id;
  19. /**
  20. * @var string
  21. */
  22. private $client_secret;
  23. /**
  24. * @var string
  25. */
  26. private $access_token_url;
  27. /**
  28. * @var string
  29. */
  30. private $user_info_url;
  31. /**
  32. * @param string $client_id
  33. * @param string $client_secret
  34. * @param string $access_token_url
  35. * @param string $user_info_url
  36. */
  37. public function __construct($client_id, $client_secret, $access_token_url, $user_info_url)
  38. {
  39. $this->client_id = $client_id;
  40. $this->client_secret = $client_secret;
  41. $this->access_token_url = $access_token_url;
  42. $this->user_info_url = $user_info_url;
  43. }
  44. /**
  45. * @param Request $request
  46. * @param string $providerKey
  47. *
  48. * @return AnonymousToken|PreAuthenticatedToken
  49. */
  50. public function createToken(Request $request, $providerKey)
  51. {
  52. if ($request->headers->has("php-auth-user") and $request->headers->has("php-auth-pw")) {
  53. return new PreAuthenticatedToken($request->headers->get("php-auth-user"), $request->headers->get("php-auth-pw"), $providerKey);
  54. }
  55. return new AnonymousToken("anon.", "anon.");
  56. }
  57. /**
  58. * @param TokenInterface $token
  59. * @param string $providerKey
  60. *
  61. * @return boolean
  62. */
  63. public function supportsToken(TokenInterface $token, $providerKey)
  64. {
  65. return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
  66. }
  67. /**
  68. * @param TokenInterface $token
  69. * @param UserProviderInterface $userProvider
  70. * @param string $providerKey
  71. *
  72. * @return PreAuthenticatedToken
  73. */
  74. public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
  75. {
  76. $password = $token->getCredentials();
  77. $username = $token->getUsername();
  78. $browser = new \Buzz\Browser();
  79. $token = @json_decode(file_get_contents("/tmp/." . base64_encode($username . ":" . $password)), true);
  80. if (!isset($token["access_token"])) {
  81. $listener = new BasicAuthListener($this->client_id, $this->client_secret);
  82. $browser->addListener($listener);
  83. $body = ['grant_type' => 'password',
  84. 'username' => $username,
  85. 'password' => $password,
  86. ];
  87. $response = $browser->post($this->access_token_url, ['Content-Type' => 'application/x-www-form-urlencoded'], http_build_query($body));
  88. $token = json_decode($response->getContent(), true);
  89. if ($token['expires_in']) {
  90. $token["expires_at"] = time() + $token['expires_in'];
  91. } else {
  92. $token["expires_at"] = time() + 3600;
  93. }
  94. file_put_contents("/tmp/." . base64_encode($username . ":" . $password), json_encode($token));
  95. }
  96. if (isset($token["expires_at"]) and $token["expires_at"] >= time()) {
  97. $listener = new BasicAuthListener($this->client_id, $this->client_secret);
  98. $browser->addListener($listener);
  99. $body = [
  100. 'grant_type' => 'refresh_token',
  101. 'refresh_token' => $token['refresh_token'],
  102. ];
  103. $response = $browser->post($this->access_token_url, ['Content-Type' => 'application/x-www-form-urlencoded'], http_build_query($body));
  104. $token = json_decode($response->getContent(), true);
  105. if ($token['expires_in']) {
  106. $token["expires_at"] = time() + $token['expires_in'];
  107. } else {
  108. $token["expires_at"] = time() + 3600;
  109. }
  110. file_put_contents("/tmp/." . base64_encode($username . ":" . $password), json_encode($token));
  111. }
  112. if (!isset($token["user_info"])) {
  113. $oauth_headers = [
  114. "Authorization" => ucfirst($token["token_type"]) . " " . $token["access_token"],
  115. ];
  116. $response = $browser->get($this->user_info_url, $oauth_headers);
  117. $auth_info = json_decode($response->getContent(), true);
  118. $token["user_info"] = $auth_info;
  119. file_put_contents("/tmp/." . base64_encode($username . ":" . $password), json_encode($token));
  120. } else {
  121. $auth_info = $token["user_info"];
  122. }
  123. $user = $userProvider->loadUserByUsername($auth_info["username"]);
  124. $user->setRoles($auth_info["roles"]);
  125. $user->setTenancyCurrent($auth_info["tenancyCurrent"]);
  126. return new PreAuthenticatedToken($user, array(), $providerKey, $user->getRoles());
  127. }
  128. /**
  129. * @param Request $request
  130. * @param AuthenticationException $exception
  131. *
  132. * @return Response
  133. */
  134. public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
  135. {
  136. return new Response(
  137. // this contains information about *why* authentication failed
  138. // use it, or return your own message
  139. strtr($exception->getMessageKey(), $exception->getMessageData()), 401);
  140. }
  141. }