├── .gitignore ├── SteamAuthBundle.php ├── DependencyInjection ├── Configuration.php ├── SteamAuthExtension.php └── Security │ └── SteamFactory.php ├── Resources ├── views │ └── Login │ │ └── login.html.twig └── config │ └── services.yml ├── composer.json ├── Security ├── EntryPoint │ └── SteamEntryPoint.php ├── User │ ├── SteamUserInterface.php │ └── SteamUserProvider.php ├── Authentication │ └── SteamProvider.php ├── Firewall │ └── SteamListener.php └── Token │ └── SteamToken.php ├── LICENSE ├── Service └── SteamUserService.php └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | -------------------------------------------------------------------------------- /SteamAuthBundle.php: -------------------------------------------------------------------------------- 1 | getExtension('security'); 16 | $extension->addSecurityListenerFactory(new SteamFactory()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | root('steam_auth') 15 | ->children() 16 | ->scalarNode('steam_key')->end() 17 | ->scalarNode('user_class')->end() 18 | ->end() 19 | ; 20 | 21 | return $treeBuilder; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Resources/views/Login/login.html.twig: -------------------------------------------------------------------------------- 1 |
10 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sirwaddles/steamauth", 3 | "description": "Steam Authentication for Symfony", 4 | "keywords": ["Steam", "User management"], 5 | "license": "MIT", 6 | "type": "symfony-bundle", 7 | "homepage": "https://github.com/SirWaddles/SteamAuthBundle", 8 | "authors": [ 9 | { 10 | "name": "Waddles", 11 | "email": "site@sirwaddlesworth.com" 12 | } 13 | ], 14 | "autoload": { 15 | "psr-4": { 16 | "SteamAuthBundle\\": "" 17 | } 18 | }, 19 | "require": { 20 | "php": ">=5.5.9", 21 | "symfony/symfony": "^3.1", 22 | "doctrine/orm": "^2.5", 23 | "doctrine/doctrine-bundle": "^1.6", 24 | "eightpoints/guzzle-bundle": "^5.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Security/EntryPoint/SteamEntryPoint.php: -------------------------------------------------------------------------------- 1 | httpUtils = $httpUtils; 16 | } 17 | 18 | public function start(Request $request, AuthenticationException $authException = null) 19 | { 20 | return $this->httpUtils->createRedirectResponse($request, 'login'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Resources/config/services.yml: -------------------------------------------------------------------------------- 1 | services: 2 | steam.user_provider: 3 | class: SteamAuthBundle\Security\User\SteamUserProvider 4 | arguments: [ '@doctrine.orm.default_entity_manager', '@steam.user_service', '%steam_auth.user_class%' ] 5 | 6 | steam.security.authentication.provider: 7 | class: SteamAuthBundle\Security\Authentication\SteamProvider 8 | arguments: [ '@steam.user_provider', '@guzzle.client.steam' ] 9 | public: false 10 | 11 | steam.security.authentication.listener: 12 | class: SteamAuthBundle\Security\Firewall\SteamListener 13 | arguments: [ 'home', '@security.token_storage', '@security.authentication.manager', '@router' ] 14 | public: false 15 | 16 | steam.security.authentication.entry_point: 17 | class: SteamAuthBundle\Security\EntryPoint\SteamEntryPoint 18 | arguments: [ '@security.http_utils' ] 19 | public: false 20 | 21 | steam.user_service: 22 | class: SteamAuthBundle\Service\SteamUserService 23 | arguments: [ '@guzzle.client.steam_user', '%steam_auth.steam_key%' ] 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Waddlesworth 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Service/SteamUserService.php: -------------------------------------------------------------------------------- 1 | guzzle = $guzzle; 15 | $this->steamKey = $steamKey; 16 | } 17 | 18 | public function getUserData($communityId) 19 | { 20 | $response = $this->guzzle->request('GET', 'GetPlayerSummaries/v0002/', ['query' => ['steamids' => $communityId, 'key' => $this->steamKey]]); 21 | $userdata = json_decode($response->getBody(), true); 22 | if (isset($userdata['response']['players'][0])) { 23 | return $userdata['response']['players'][0]; 24 | } 25 | return NULL; 26 | } 27 | 28 | public function updateUserEntry(SteamUserInterface $user) 29 | { 30 | $userdata = $this->getUserData($user->getUsername()); 31 | $user->setNickname($userdata['personaname']); 32 | $user->setAvatar($userdata['avatar']); 33 | return $user; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Security/User/SteamUserInterface.php: -------------------------------------------------------------------------------- 1 | processConfiguration($configuration, $configs); 16 | $container->setParameter('steam_auth.steam_key', $config['steam_key']); 17 | $container->setParameter('steam_auth.user_class', $config['user_class']); 18 | 19 | $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 20 | $loader->load('services.yml'); 21 | } 22 | 23 | public function prepend(ContainerBuilder $container) 24 | { 25 | $config = [ 26 | 'clients' => [ 27 | 'steam' => [ 28 | 'base_url' => 'http://steamcommunity.com/openid/', 29 | ], 30 | 'steam_user' => [ 31 | 'base_url' => 'http://api.steampowered.com/ISteamUser/', 32 | ], 33 | ] 34 | ]; 35 | 36 | $container->prependExtensionConfig('guzzle', $config); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Security/Authentication/SteamProvider.php: -------------------------------------------------------------------------------- 1 | userProvider = $userProvider; 19 | $this->guzzle = $guzzle; 20 | } 21 | 22 | public function authenticate(TokenInterface $token) 23 | { 24 | if ($token->getAttribute('openid.ns') != "http://specs.openid.net/auth/2.0") { 25 | throw new AuthenticationException('Invalid Token'); 26 | } 27 | 28 | $checkAuth = $token->getAttributes(); 29 | $checkAuth['openid.mode'] = 'check_authentication'; 30 | $response = $this->guzzle->request('GET', 'login', ['query' => $checkAuth]); 31 | 32 | if ((string)$response->getBody() == "ns:http://specs.openid.net/auth/2.0\nis_valid:true\n") { 33 | $user = $this->userProvider->loadUserByUsername($token->getUsername()); 34 | $token->setUser($user); 35 | $token->setAuthenticated(true); 36 | } 37 | 38 | return $token; 39 | } 40 | 41 | public function supports(TokenInterface $token) 42 | { 43 | return $token instanceof SteamToken; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Security/User/SteamUserProvider.php: -------------------------------------------------------------------------------- 1 | em = $em; 21 | $this->userClass = $userClass; 22 | $this->userService = $userService; 23 | } 24 | 25 | public function loadUserByUsername($username) 26 | { 27 | $userRepo = $this->em->getRepository($this->userClass); 28 | $user = $userRepo->findOneBy(['username' => $username]); 29 | 30 | if (!$user) { 31 | $user = new $this->userClass(); 32 | $user->setUsername($username); 33 | $user->setPassword(base64_encode(random_bytes(20))); 34 | $this->userService->updateUserEntry($user); 35 | 36 | $this->em->persist($user); 37 | $this->em->flush($user); 38 | } 39 | 40 | return $user; 41 | } 42 | 43 | public function refreshUser(UserInterface $user) 44 | { 45 | if (!$user instanceof SteamUserInterface) { 46 | throw new UnsupportedUserException("User not supported"); 47 | } 48 | return $this->loadUserByUsername($user->getUsername()); 49 | } 50 | 51 | public function supportsClass($class) 52 | { 53 | return $class === $this->userClass; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /DependencyInjection/Security/SteamFactory.php: -------------------------------------------------------------------------------- 1 | setDefinition($providerId, new DefinitionDecorator('steam.security.authentication.provider')) 18 | ->replaceArgument(0, new Reference($userProvider)) 19 | ; 20 | 21 | $listenerId = 'security.authentication.listener.steam.'.$id; 22 | $listener = $container 23 | ->setDefinition($listenerId, new DefinitionDecorator('steam.security.authentication.listener')) 24 | ->replaceArgument(0, $config['default_route']) 25 | ->addMethodCall('setProviderKey', [$id]) 26 | ->addTag('security.remember_me_aware', ['id' => $id, 'provider' => $userProvider]) 27 | ; 28 | 29 | $entryPointId = 'security.authentication.entry_point.steam.' . $id; 30 | $container->setDefinition($entryPointId, new DefinitionDecorator('steam.security.authentication.entry_point')); 31 | 32 | return array($providerId, $listenerId, $entryPointId); 33 | } 34 | 35 | public function getPosition() 36 | { 37 | return 'pre_auth'; 38 | } 39 | 40 | public function getKey() 41 | { 42 | return 'steam'; 43 | } 44 | 45 | public function addConfiguration(NodeDefinition $node) 46 | { 47 | $builder = $node->children(); 48 | $builder 49 | ->scalarNode('default_route')->end() 50 | ; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SteamAuthBundle 2 | Steam Authentication for Symfony 3 | 4 | ## Configuration and Usage 5 | A couple things are necessary for this bundle to work. Your user class will have to be managed by Doctrine ORM (does not support Mongo or Propel at the moment.) 6 | At first, add the EightPoints GuzzleBundle and the SteamAuthBundle to your AppKernel.php 7 | ```php 8 | $bundles = [ 9 | ... 10 | new EightPoints\Bundle\GuzzleBundle\GuzzleBundle(), 11 | new SteamAuthBundle\SteamAuthBundle() 12 | ... 13 | ]; 14 | ``` 15 | 16 | In the `app/config/config.yml` you will need the following parameters 17 | ```yml 18 | steam_auth: 19 | steam_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 20 | user_class: AppBundle\Entity\User 21 | ``` 22 | 23 | And your security yml firewall will need 24 | * `steam` as a firewall option 25 | * with a `default_route` option with the name of the route to go to once a user has logged in 26 | * a user provider marked as `steam.user_provider` 27 | 28 | ```yml 29 | security: 30 | providers: 31 | steamauth: 32 | id: steam.user_provider 33 | 34 | firewalls: 35 | main: 36 | provider: steamauth 37 | steam: 38 | default_route: home 39 | ``` 40 | 41 | Your User class will need to implement `SteamAuthBundle\Security\User\SteamUserInterface` as well as `Symfony\Component\Security\Core\User\UserInterface` 42 | 43 | Note that this bundle will create a new instance of your user class with an empty default constructor, will set the username, nickname, avatar and password, and will persist it to the database. This occurs when a user signs in with their steam account and do not already exist in your database. 44 | 45 | This bundle also works with Symfony's Remember Me functionality if you wish to use it. 46 | 47 | ```yml 48 | main: 49 | steam: 50 | default_route: home 51 | remember_me: 52 | secret: '%secret%' 53 | ``` 54 | 55 | ## Login Template 56 | 57 | On your login page, you can either use your own form with the OpenID parameters, or include the SteamAuthBundle Template 58 | ```twig 59 | {% include "SteamAuthBundle:Login:login.html.twig" %} 60 | ``` 61 | -------------------------------------------------------------------------------- /Security/Firewall/SteamListener.php: -------------------------------------------------------------------------------- 1 | defaultRoute = $defaultRoute; 30 | $this->tokenStorage = $tokenStorage; 31 | $this->authenticationManager = $authenticationManager; 32 | $this->router = $router; 33 | } 34 | 35 | public function setProviderKey($providerKey) 36 | { 37 | $this->providerKey = $providerKey; 38 | } 39 | 40 | public function getProviderKey($providerKey) 41 | { 42 | return $this->providerKey; 43 | } 44 | 45 | public function setRememberMeServices(RememberMeServicesInterface $rememberMeServices) 46 | { 47 | $this->rememberMeServices = $rememberMeServices; 48 | } 49 | 50 | public function handle(GetResponseEvent $event) 51 | { 52 | $request = $event->getRequest(); 53 | if ($request->get('_route') != 'login_check') { 54 | return; 55 | } 56 | 57 | $token = new SteamToken(); 58 | $username = $request->query->get('openid_claimed_id'); 59 | $username = str_replace("http://steamcommunity.com/openid/id/", "", $username); 60 | $username = str_replace("https://steamcommunity.com/openid/id/", "", $username); 61 | $token->setUsername($username); 62 | $token->setAttributes($request->query->all()); 63 | 64 | $authToken = $this->authenticationManager->authenticate($token); 65 | $this->tokenStorage->setToken($authToken); 66 | 67 | $targetPath = $this->getTargetPath($request->getSession(), $this->providerKey); 68 | if ($targetPath !== null) { 69 | $this->removeTargetPath($request->getSession(), $this->providerKey); 70 | } else { 71 | $targetPath = $this->router->generate($this->defaultRoute); 72 | } 73 | 74 | $response = new RedirectResponse($targetPath); 75 | if ($this->rememberMeServices !== null) { 76 | $this->rememberMeServices->loginSuccess($request, $response, $token); 77 | } 78 | $event->setResponse($response); 79 | 80 | return; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Security/Token/SteamToken.php: -------------------------------------------------------------------------------- 1 | getUsername(); 19 | } 20 | 21 | public function getRoles() 22 | { 23 | return $this->roles; 24 | } 25 | 26 | public function addRole($role) 27 | { 28 | if ($role instanceof RoleInterface) { 29 | $this->roles[] = $role; 30 | } else { 31 | $this->roles[] = new Role($role); 32 | } 33 | return $this; 34 | } 35 | 36 | public function getCredentials() 37 | { 38 | return ''; 39 | } 40 | 41 | public function getUser() 42 | { 43 | return $this->user; 44 | } 45 | 46 | public function setUser($user) 47 | { 48 | $this->roles = []; 49 | foreach ($user->getRoles() as $role) { 50 | $this->roles[] = new Role($role); 51 | } 52 | $this->user = $user; 53 | return $this; 54 | } 55 | 56 | public function getUsername() 57 | { 58 | return $this->user ? $this->user->getUsername() : $this->username; 59 | } 60 | 61 | public function setUsername($username) 62 | { 63 | $this->username = $username; 64 | return $this; 65 | } 66 | 67 | public function isAuthenticated() 68 | { 69 | return $this->authenticated; 70 | } 71 | 72 | public function setAuthenticated($authenticated) 73 | { 74 | $this->authenticated = $authenticated; 75 | return $this; 76 | } 77 | 78 | public function eraseCredentials() 79 | { 80 | 81 | } 82 | 83 | public function getAttributes() 84 | { 85 | return $this->attributes; 86 | } 87 | 88 | public function setAttributes(array $attributes) 89 | { 90 | $this->attributes = []; 91 | foreach ($attributes as $key => $attribute) { 92 | $key = str_replace("openid_", "openid.", $key); 93 | $this->attributes[$key] = $attribute; 94 | } 95 | return $this; 96 | } 97 | 98 | public function hasAttribute($name) 99 | { 100 | return isset($this->attributes[$name]); 101 | } 102 | 103 | public function getAttribute($name) 104 | { 105 | return isset($this->attributes[$name]) ? $this->attributes[$name] : null; 106 | } 107 | 108 | public function setAttribute($name, $value) 109 | { 110 | $this->attributes[$name] = $value; 111 | } 112 | 113 | public function serialize() 114 | { 115 | return serialize([ 116 | 'attributes' => $this->attributes, 117 | 'authenticated' => $this->isAuthenticated(), 118 | 'username' => $this->getUsername(), 119 | 'roles' => $this->getRoles(), 120 | 'user' => $this->getUser(), 121 | ]); 122 | } 123 | 124 | public function unserialize($data) 125 | { 126 | $data = unserialize($data); 127 | $this->attributes = $data['attributes']; 128 | $this->setAuthenticated($data['authenticated']); 129 | $this->setUsername($data['username']); 130 | $this->setUser($data['user']); 131 | $this->roles = $data['roles']; 132 | } 133 | } 134 | --------------------------------------------------------------------------------