Pārlūkot izejas kodu

Add fb, github, google ouath code using hwi/oauth-bundle

jmontoyaa 8 gadi atpakaļ
vecāks
revīzija
41c4689572

+ 1 - 1
app/AppKernel.php

@@ -71,7 +71,7 @@ class AppKernel extends Kernel
             //new Sonata\DoctrinePHPCRAdminBundle\SonataDoctrinePHPCRAdminBundle(),
 
             // Oauth
-            //new HWI\Bundle\OAuthBundle\HWIOAuthBundle(),
+            new HWI\Bundle\OAuthBundle\HWIOAuthBundle(),
 
             //new Gregwar\CaptchaBundle\GregwarCaptchaBundle(),
             new Mopa\Bundle\BootstrapBundle\MopaBootstrapBundle(),

+ 41 - 7
app/config/config.yml

@@ -281,13 +281,47 @@ fm_elfinder:
 knp_menu:
     twig: true
 #
-#hwi_oauth:
-#    firewall_names: [main]
-#    resource_owners:
-#        any_name:
-#            type:                github
-#            client_id:           <client_id>
-#            client_secret:       <client_secret>
+hwi_oauth:
+    connect:
+        account_connector: chamilo_user_provider
+    firewall_names: [secured_area]
+    resource_owners:
+        github:
+            type:                github
+            client_id:           <client_id>
+            client_secret:       <client_secret>
+        facebook:
+            type:                facebook
+            client_id:           <client_id>
+            client_secret:       <client_secret>
+        google:
+            type:                google
+            client_id:           <client_id>
+            client_secret:       <client_secret>
+            scope:               "email profile"
+        my_custom_oauth2:
+            type:                oauth2
+            client_id:           <client_id>
+            client_secret:       <client_secret>
+            access_token_url:    https://path.to/oauth/v2/token
+            authorization_url:   https://path.to/oauth/v2/authorize
+            infos_url:           https://path.to/api/user
+            scope:               "user_details"
+            user_response_class: HWI\Bundle\OAuthBundle\OAuth\Response\PathUserResponse
+            paths:
+                identifier: id
+                nickname:   username
+                realname:   fullname
+    fosub:
+        # try 30 times to check if a username is available (foo, foo1, foo2 etc)
+        username_iterations: 30
+
+        # mapping between resource owners (see below) and properties
+        properties:
+            github: githubId
+            google: googleId
+            facebook: facebookId
+            my_custom_provider: customId
 
 #gregwar_captcha:
 

+ 1 - 1
app/config/fos/fos_user.yml

@@ -1,6 +1,6 @@
 fos_user:
     db_driver: orm # can be orm or odm
-    firewall_name:  main
+    firewall_name:  secured_area
 
     # if you change the class configuration, please also alter the sonata_user.yml file
     user_class:     Chamilo\UserBundle\Entity\User

+ 21 - 8
app/config/routing.yml

@@ -1,4 +1,3 @@
-
 home:
     path: ../../index.php
 
@@ -33,13 +32,27 @@ admin:
     resource: '@SonataAdminBundle/Resources/config/routing/sonata_admin.xml'
     prefix: /{_locale}/administration
 
-#hwi_oauth_redirect:
-#    resource: "@HWIOAuthBundle/Resources/config/routing/redirect.xml"
-#    prefix:   /connect
-#
-#hwi_oauth_login:
-#    resource: "@HWIOAuthBundle/Resources/config/routing/login.xml"
-#    prefix:   /login
+# HWIOAuthBundle routes
+hwi_oauth_redirect:
+    resource: "@HWIOAuthBundle/Resources/config/routing/redirect.xml"
+    prefix:   /connect
+
+hwi_oauth_connect:
+    resource: "@HWIOAuthBundle/Resources/config/routing/connect.xml"
+    prefix:   /connect
+
+hwi_oauth_login:
+    resource: "@HWIOAuthBundle/Resources/config/routing/login.xml"
+    prefix:   /connect
+
+facebook_login:
+    path: /connect/check-facebook
+
+google_login:
+    path: /connect/check-google
+
+github_login:
+    path: /connect/check-github
 
 logout:
     path: /logout

+ 14 - 3
app/config/security.yml

@@ -22,7 +22,6 @@ security:
             - ROLE_CURRENT_COURSE_TEACHER
             - SONATA
         ROLE_SUPER_ADMIN: [ROLE_SONATA_ADMIN, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
-
         ROLE_GLOBAL_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
         ROLE_RRHH: [ROLE_TEACHER]
         ROLE_TEACHER: [ROLE_STUDENT]
@@ -55,7 +54,7 @@ security:
             pattern: ^/(_(profiler|wdt)|css|images|js)/
             security: false
 
-        main:
+        secured_area:
             pattern: .*
             context: user
             form_login:
@@ -72,6 +71,18 @@ security:
                 success_handler: chamilo_core.listener.logout_success_handler
                 invalidate_session: false
 #                handlers: ['sonata.page.cms_manager_selector']
-            anonymous: ~
+            anonymous: true
+            oauth:
+                resource_owners:
+                    facebook:        "/login/check-facebook"
+                    google:          "/login/check-google"
+                    github:          "/login/check-github"
+                login_path:        /login
+                failure_path:      /connect
+                use_forward:       false
+
+                oauth_user_provider:
+                    service: chamilo_user_provider
+
             switch_user: false
 

+ 2 - 0
app/config/sonata/sonata_page.yml

@@ -29,6 +29,8 @@ sonata_page:
         - ^/api/(.*)
         - ^install
         - ^/install/(.*)
+        - ^/login/(.*)
+        - ^/connect/(.*)
         - ^/packages/(.*)
         - ^/package/(.*)
         - install.php

+ 1 - 1
composer.json

@@ -162,7 +162,7 @@
         "jeroendesloovere/vcard": "^1.2",
         "stof/doctrine-extensions-bundle": "~1.0",
         "alchemy/zippy": "^0.2.1",
-        "hwi/oauth-bundle": "^0.4.0",
+        "hwi/oauth-bundle": "~0.5",
         "genemu/form-bundle": "2.2.*",
         "oneup/flysystem-bundle": "1.7.*",
         "intervention/image": "^2.3",

+ 66 - 0
src/Chamilo/CourseBundle/Resources/config/routing.yml

@@ -0,0 +1,66 @@
+course_url:
+    path: courses
+#    resource: '@ChamiloCoreBundle/Controller/Admin'
+
+core_tool:
+    resource: '@ChamiloCourseBundle/Controller'
+    type: annotation
+    prefix: /courses/{course}/
+#    type: annotation
+
+core_tool_document:
+    pattern: /courses/{course}/document/{file}
+    defaults:
+        _controller: ChamiloCoreBundle:Resource:getDocument
+    requirements:
+        file: .+ # allow "/" in {file}
+
+chamilo_course_tool_intro_create:
+    path: /courses/{course}/introduction/{tool}/create/
+    methods: [GET, POST]
+    defaults:
+        _controller: ChamiloCourseBundle:CToolIntro:create
+    requirements:
+        tool: "[a-zA-Z_]+"
+
+chamilo_course_tool_intro_update:
+    path: /courses/{course}/introduction/{tool}/update/
+    methods: [GET]
+    defaults:
+        _controller: chamilo_course.controller.c_tool_intro:updateAction
+
+chamilo_course_tool_list:
+    path: /courses/{course}/introduction
+    methods: [GET]
+    defaults:
+        _controller: chamilo_course.controller.tool:indexAction
+
+
+#chamilo_course.c_tool_intro:
+#    resource: |
+#        alias: chamilo_course.c_tool_intro
+#        path: /courses/{course}/introduction/{tool}
+#        templates: :Admin/Book
+#    type: sylius.resource_api
+
+
+# Redirects /url/ to /url
+remove_trailing_slash:
+    path: /{url}
+    defaults: { _controller: ChamiloCoreBundle:Redirecting:removeTrailingSlash }
+    requirements:
+        url: .*/$
+        _method: GET
+
+## Course settings
+chamilo_course_settings:
+    pattern: /courses/{course}/settings/{namespace}
+    defaults:
+        _controller: ChamiloCourseBundle:Settings:update
+        template: ChamiloCourseBundle:Settings:default.html.twig
+
+chamilo_course_tool_index:
+    pattern: /courses/{course}/tools
+    methods: [GET, POST, HEAD, DELETE]
+    defaults:
+        _controller: chamilo_course.controller.tool:indexAction

+ 1 - 0
src/Chamilo/UserBundle/DependencyInjection/ChamiloUserExtension.php

@@ -22,5 +22,6 @@ class ChamiloUserExtension extends Extension
     {
         $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
         $loader->load('admin.yml');
+        $loader->load('services.yml');
     }
 }

+ 1 - 1
src/Chamilo/UserBundle/Entity/Manager/UserManager.php

@@ -17,7 +17,7 @@ class UserManager extends BaseUserManager
      *
      * @param string $token
      *
-     * @return UserInterface
+     * @return UserManager
      */
     public function findUserByConfirmationToken($token)
     {

+ 132 - 3
src/Chamilo/UserBundle/Entity/User.php

@@ -321,6 +321,36 @@ class User extends BaseUser implements ThemeUser
      */
     //protected $lastLogin;
 
+    /**
+     * @ORM\Column(name="facebook_id", type="string", length=255, nullable=true)
+     */
+    protected $facebookId;
+
+    /**
+     * @ORM\Column(name="facebook_access_token", type="string", length=255, nullable=true)
+     */
+    protected $facebookAccessToken;
+
+    /**
+     * @ORM\Column(name="google_id", type="string", length=255, nullable=true)
+     */
+    protected $googleId;
+
+    /**
+     * @ORM\Column(name="google_access_token", type="string", length=255, nullable=true)
+     */
+    protected $googleAccessToken;
+
+    /**
+     * @ORM\Column(name="github_id", type="string", length=255, nullable=true)
+     */
+    protected $githubId;
+
+    /**
+     * @ORM\Column(name="github_access_token", type="string", length=255, nullable=true)
+     */
+    protected $githubAccessToken;
+
     /**
      * @var \DateTime
      * @ORM\Column(name="created_at", type="datetime", nullable=true, unique=false)
@@ -1311,7 +1341,7 @@ class User extends BaseUser implements ThemeUser
     }
 
     /**
-     * @return Media
+     * @return string
      */
     public function getAvatar()
     {
@@ -1321,12 +1351,12 @@ class User extends BaseUser implements ThemeUser
     /**
      * @return string
      */
-    public function getAvatarOrAnonymous()
+    public function getAvatarOrAnonymous($size = 22)
     {
         $avatar = $this->getAvatar();
 
         if (empty($avatar)) {
-            return 'bundles/chamilocore/img/unknown.jpg';
+            return "img/icons/$size/unknown.png";
         }
 
         return $avatar;
@@ -2486,4 +2516,103 @@ class User extends BaseUser implements ThemeUser
     {
         return $this->currentUrl;
     }
+
+    /**
+     * @return mixed
+     */
+    public function getFacebookId()
+    {
+        return $this->facebookId;
+    }
+
+    /**
+     * @param mixed $facebookId
+     */
+    public function setFacebookId($facebookId)
+    {
+        $this->facebookId = $facebookId;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getFacebookAccessToken()
+    {
+        return $this->facebookAccessToken;
+    }
+
+    /**
+     * @param mixed $facebookAccessToken
+     */
+    public function setFacebookAccessToken($facebookAccessToken)
+    {
+        $this->facebookAccessToken = $facebookAccessToken;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getGoogleId()
+    {
+        return $this->googleId;
+    }
+
+    /**
+     * @param mixed $googleId
+     */
+    public function setGoogleId($googleId)
+    {
+        $this->googleId = $googleId;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getGoogleAccessToken()
+    {
+        return $this->googleAccessToken;
+    }
+
+    /**
+     * @param mixed $googleAccessToken
+     */
+    public function setGoogleAccessToken($googleAccessToken)
+    {
+        $this->googleAccessToken = $googleAccessToken;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getGithubId()
+    {
+        return $this->githubId;
+    }
+
+    /**
+     * @param mixed $githubId
+     */
+    public function setGithubId($githubId)
+    {
+        $this->githubId = $githubId;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getGithubAccessToken()
+    {
+        return $this->githubAccessToken;
+    }
+
+    /**
+     * @param mixed $githubAccessToken
+     */
+    public function setGithubAccessToken($githubAccessToken)
+    {
+        $this->githubAccessToken = $githubAccessToken;
+    }
+
+
+
 }

+ 5 - 0
src/Chamilo/UserBundle/Resources/config/services.yml

@@ -0,0 +1,5 @@
+services:
+    chamilo_user_provider:
+        class: Chamilo\UserBundle\Security\FOSUBUserProvider
+        #this is the place where the properties are passed to the UserProvider - see config.yml
+        arguments: [@fos_user.user_manager,{facebook: facebookId, google: googleId, github: githubId}]

+ 20 - 33
src/Chamilo/UserBundle/Resources/views/Security/login.html.twig

@@ -9,51 +9,38 @@
         {% endblock %}
         <div class="login-box-body">
             {% block sonata_user_login_form %}
-                <form action="{{ path("fos_user_security_check") }}"
-                      method="post" role="form">
-                    <input type="hidden" name="_csrf_token"
-                           value="{{ csrf_token('authenticate') }}"/>
+                <form action="{{ path("sonata_user_admin_security_check") }}" method="post" role="form">
+                    <input type="hidden" name="_csrf_token" value="{{ csrf_token }}"/>
 
                     <div class="form-group has-feedback">
-                        <label for="username"
-                               class="col-sm-4 control-label">{{ 'security.login.username'|trans({}, 'FOSUserBundle') }}</label>
-
-                        <input type="text" class="form-control" id="username"
-                               name="_username" value="{{ last_username }}"
-                               required="required"/>
+                        <input type="text" class="form-control" id="username"  name="_username" value="{{ last_username }}" required="required" placeholder="{{ 'security.login.username'|trans({}, 'SonataUserBundle') }}"/>
+                        <span class="glyphicon glyphicon-user form-control-feedback"></span>
                     </div>
 
                     <div class="form-group has-feedback">
-                        <label for="password"
-                               class="col-sm-4 control-label">{{ 'security.login.password'|trans({}, 'FOSUserBundle') }}</label>
-
-                        <input type="password" class="form-control"
-                               id="password"
-                               name="_password" required="required"/>
+                        <input type="password" class="form-control" id="password" name="_password" required="required" placeholder="{{ 'security.login.password'|trans({}, 'SonataUserBundle') }}"/>
+                        <span class="glyphicon glyphicon-lock form-control-feedback"></span>
                     </div>
 
-                    <div class="form-group has-feedback">
-                        <div class="checkbox control-group">
-                            <label for="remember_me">
-                                <input type="checkbox" id="remember_me"
-                                       name="_remember_me" value="on"/>
-                                {{ 'security.login.remember_me'|trans({}, 'FOSUserBundle') }}
-                            </label>
-                        </div>
+                     <div class="form-group has-feedback">
+                        <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" id="remember_me" name="_remember_me" value="on"/>
+                                    {{ 'security.login.remember_me'|trans({}, 'FOSUserBundle') }}
+                                </label>
+                            </div>
                     </div>
 
-                    <div class="form-group has-feedback">
-                        <a href="{{ path('main', { name: 'auth/lostPassword.php' }) }}">{{ 'forgotten_password'|trans({}, 'SonataUserBundle') }}</a>
-                    </div>
-
-                    <div class="form-group">
-                        <div class="col-sm-offset-4 col-sm-8">
-                            <input type="submit" id="_submit" name="_submit"
-                                   class="btn btn-primary"
-                                   value="{{ 'security.login.submit'|trans({}, 'FOSUserBundle') }}"/>
+                    <div class="row">
+                        <div class="col-xs-12">
+                            <button type="submit" class="btn btn-primary btn-block btn-flat">
+                                {{ 'security.login.submit'|trans({}, 'FOSUserBundle') }}</button>
                         </div>
                     </div>
                 </form>
+
+                <a href="{{ path('main', { name: 'auth/lostPassword.php' }) }}">{{ 'forgotten_password'|trans({}, 'SonataUserBundle') }}</a>
+
             {% endblock %}
         </div>
     {% endblock %}

+ 69 - 0
src/Chamilo/UserBundle/Security/FOSUBUserProvider.php

@@ -0,0 +1,69 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\UserBundle\Security;
+use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
+use HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider as BaseFOSUBProvider;
+use Symfony\Component\Security\Core\User\UserInterface;
+
+class FOSUBUserProvider extends BaseFOSUBProvider
+{
+    /**
+     * {@inheritDoc}
+     */
+    public function connect(UserInterface $user, UserResponseInterface $response)
+    {
+        $property = $this->getProperty($response);
+        $username = $response->getUsername();
+        //on connect - get the access token and the user ID
+        $service = $response->getResourceOwner()->getName();
+        $setter = 'set'.ucfirst($service);
+        $setterId = $setter.'Id';
+        $setter_token = $setter.'AccessToken';
+        //we "disconnect" previously connected users
+        if (null !== $previousUser = $this->userManager->findUserBy(array($property => $username))) {
+            $previousUser->$setterId(null);
+            $previousUser->$setter_token(null);
+            $this->userManager->updateUser($previousUser);
+        }
+        // We connect current user
+        $user->$setterId($username);
+        $user->$setter_token($response->getAccessToken());
+        $this->userManager->updateUser($user);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function loadUserByOAuthUserResponse(UserResponseInterface $response)
+    {
+        $username = $response->getUsername();
+        $user = $this->userManager->findUserBy(array($this->getProperty($response) => $username));
+        // User creation
+        if (null === $user) {
+            $service = $response->getResourceOwner()->getName();
+            $setter = 'set'.ucfirst($service);
+            $setterId = $setter.'Id';
+            $setterToken = $setter.'AccessToken';
+            // create new user here
+            $user = $this->userManager->createUser();
+            $user->$setterId($username);
+            $user->$setterToken($response->getAccessToken());
+            //I have set all requested data with the user's username
+            //modify here with relevant data
+            $user->setUsername($username);
+            $user->setEmail($username);
+            $user->setPassword($username);
+            $user->setEnabled(true);
+            $this->userManager->updateUser($user);
+            return $user;
+        }
+        //if user exists - go with the HWIOAuth way
+        $user = parent::loadUserByOAuthUserResponse($response);
+        $serviceName = $response->getResourceOwner()->getName();
+        $setter = 'set' . ucfirst($serviceName) . 'AccessToken';
+        //update access token
+        $user->$setter($response->getAccessToken());
+        return $user;
+    }
+}