diff options
author | Nicolas LÅ“uillet <nicolas@loeuillet.org> | 2015-09-29 14:31:52 +0200 |
---|---|---|
committer | Jeremy Benoist <jeremy.benoist@gmail.com> | 2015-10-03 13:30:43 +0200 |
commit | fcb1fba5c2fdb12c9f4041bd334aaced6f302d91 (patch) | |
tree | 0f388190a3648127c06dd3b4b9b198d2505bb7a8 | |
parent | 8a60bc4cc2b6b1cfb5d8beb7ddcafc51d89a64c9 (diff) | |
download | wallabag-fcb1fba5c2fdb12c9f4041bd334aaced6f302d91.tar.gz wallabag-fcb1fba5c2fdb12c9f4041bd334aaced6f302d91.tar.zst wallabag-fcb1fba5c2fdb12c9f4041bd334aaced6f302d91.zip |
* public registration
* remove WSSE implementation
* add oAuth2 implementation
33 files changed, 551 insertions, 528 deletions
diff --git a/app/AppKernel.php b/app/AppKernel.php index 08e14b8f..6f8c3a6d 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php | |||
@@ -26,6 +26,7 @@ class AppKernel extends Kernel | |||
26 | new Wallabag\ApiBundle\WallabagApiBundle(), | 26 | new Wallabag\ApiBundle\WallabagApiBundle(), |
27 | new Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle(), | 27 | new Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle(), |
28 | new Lexik\Bundle\FormFilterBundle\LexikFormFilterBundle(), | 28 | new Lexik\Bundle\FormFilterBundle\LexikFormFilterBundle(), |
29 | new FOS\OAuthServerBundle\FOSOAuthServerBundle(), | ||
29 | ); | 30 | ); |
30 | 31 | ||
31 | if (in_array($this->getEnvironment(), array('dev', 'test'))) { | 32 | if (in_array($this->getEnvironment(), array('dev', 'test'))) { |
diff --git a/app/config/config.yml b/app/config/config.yml index f623ab23..adf68d6c 100644 --- a/app/config/config.yml +++ b/app/config/config.yml | |||
@@ -157,3 +157,17 @@ fos_user: | |||
157 | db_driver: orm | 157 | db_driver: orm |
158 | firewall_name: main | 158 | firewall_name: main |
159 | user_class: Wallabag\CoreBundle\Entity\User | 159 | user_class: Wallabag\CoreBundle\Entity\User |
160 | registration: | ||
161 | form: | ||
162 | type: wallabag_user_registration | ||
163 | confirmation: | ||
164 | enabled: true | ||
165 | |||
166 | fos_oauth_server: | ||
167 | db_driver: orm | ||
168 | client_class: Wallabag\ApiBundle\Entity\Client | ||
169 | access_token_class: Wallabag\ApiBundle\Entity\AccessToken | ||
170 | refresh_token_class: Wallabag\ApiBundle\Entity\RefreshToken | ||
171 | auth_code_class: Wallabag\ApiBundle\Entity\AuthCode | ||
172 | service: | ||
173 | user_provider: fos_user.user_manager | ||
diff --git a/app/config/config_prod.yml b/app/config/config_prod.yml index c45f0fa6..342837a0 100644 --- a/app/config/config_prod.yml +++ b/app/config/config_prod.yml | |||
@@ -17,11 +17,6 @@ monolog: | |||
17 | type: fingers_crossed | 17 | type: fingers_crossed |
18 | action_level: error | 18 | action_level: error |
19 | handler: nested | 19 | handler: nested |
20 | wsse: | ||
21 | type: stream | ||
22 | path: %kernel.logs_dir%/%kernel.environment%.wsse.log | ||
23 | level: error | ||
24 | channels: [wsse] | ||
25 | nested: | 20 | nested: |
26 | type: stream | 21 | type: stream |
27 | path: "%kernel.logs_dir%/%kernel.environment%.log" | 22 | path: "%kernel.logs_dir%/%kernel.environment%.log" |
diff --git a/app/config/routing.yml b/app/config/routing.yml index e8bf08a5..dabb48fa 100644 --- a/app/config/routing.yml +++ b/app/config/routing.yml | |||
@@ -30,3 +30,9 @@ homepage: | |||
30 | defaults: { _controller: WallabagCoreBundle:Entry:showUnread, page : 1 } | 30 | defaults: { _controller: WallabagCoreBundle:Entry:showUnread, page : 1 } |
31 | requirements: | 31 | requirements: |
32 | page: \d+ | 32 | page: \d+ |
33 | |||
34 | fos_user: | ||
35 | resource: "@FOSUserBundle/Resources/config/routing/all.xml" | ||
36 | |||
37 | fos_oauth_server_token: | ||
38 | resource: "@FOSOAuthServerBundle/Resources/config/routing/token.xml" | ||
diff --git a/app/config/security.yml b/app/config/security.yml index 98846656..6533a430 100644 --- a/app/config/security.yml +++ b/app/config/security.yml | |||
@@ -1,9 +1,6 @@ | |||
1 | security: | 1 | security: |
2 | encoders: | 2 | encoders: |
3 | Wallabag\CoreBundle\Entity\User: | 3 | FOS\UserBundle\Model\UserInterface: sha512 |
4 | algorithm: sha1 | ||
5 | encode_as_base64: false | ||
6 | iterations: 1 | ||
7 | 4 | ||
8 | role_hierarchy: | 5 | role_hierarchy: |
9 | ROLE_ADMIN: ROLE_USER | 6 | ROLE_ADMIN: ROLE_USER |
@@ -18,11 +15,15 @@ security: | |||
18 | # the main part of the security, where you can set up firewalls | 15 | # the main part of the security, where you can set up firewalls |
19 | # for specific sections of your app | 16 | # for specific sections of your app |
20 | firewalls: | 17 | firewalls: |
21 | wsse_secured: | 18 | oauth_token: |
22 | pattern: /api/.* | 19 | pattern: ^/oauth/v2/token |
23 | wsse: true | 20 | security: false |
24 | stateless: true | 21 | api: |
25 | anonymous: true | 22 | pattern: /api/.* |
23 | fos_oauth: true | ||
24 | stateless: true | ||
25 | anonymous: false | ||
26 | |||
26 | login_firewall: | 27 | login_firewall: |
27 | pattern: ^/login$ | 28 | pattern: ^/login$ |
28 | anonymous: ~ | 29 | anonymous: ~ |
@@ -45,9 +46,9 @@ security: | |||
45 | target: / | 46 | target: / |
46 | 47 | ||
47 | access_control: | 48 | access_control: |
48 | - { path: ^/api/salt, roles: IS_AUTHENTICATED_ANONYMOUSLY } | ||
49 | - { path: ^/api/doc, roles: IS_AUTHENTICATED_ANONYMOUSLY } | 49 | - { path: ^/api/doc, roles: IS_AUTHENTICATED_ANONYMOUSLY } |
50 | - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } | 50 | - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } |
51 | - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } | ||
51 | - { path: ^/forgot-password, roles: IS_AUTHENTICATED_ANONYMOUSLY } | 52 | - { path: ^/forgot-password, roles: IS_AUTHENTICATED_ANONYMOUSLY } |
52 | - { path: /(unread|starred|archive).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } | 53 | - { path: /(unread|starred|archive).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } |
53 | - { path: ^/, roles: ROLE_USER } | 54 | - { path: ^/, roles: ROLE_USER } |
diff --git a/app/config/services.yml b/app/config/services.yml index 965bc319..ff6a582b 100644 --- a/app/config/services.yml +++ b/app/config/services.yml | |||
@@ -1,9 +1,4 @@ | |||
1 | # Learn more about services, parameters and containers at | ||
2 | # http://symfony.com/doc/current/book/service_container.html | ||
3 | parameters: | 1 | parameters: |
4 | security.authentication.provider.dao.class: Wallabag\CoreBundle\Security\Authentication\Provider\WallabagAuthenticationProvider | ||
5 | security.encoder.digest.class: Wallabag\CoreBundle\Security\Authentication\Encoder\WallabagPasswordEncoder | ||
6 | security.validator.user_password.class: Wallabag\CoreBundle\Security\Validator\WallabagUserPasswordValidator | ||
7 | lexik_form_filter.get_filter.doctrine_orm.class: Wallabag\CoreBundle\Event\Subscriber\CustomDoctrineORMSubscriber | 2 | lexik_form_filter.get_filter.doctrine_orm.class: Wallabag\CoreBundle\Event\Subscriber\CustomDoctrineORMSubscriber |
8 | 3 | ||
9 | services: | 4 | services: |
diff --git a/composer.json b/composer.json index babe9356..22cb277c 100644 --- a/composer.json +++ b/composer.json | |||
@@ -53,7 +53,8 @@ | |||
53 | "pagerfanta/pagerfanta": "~1.0.3", | 53 | "pagerfanta/pagerfanta": "~1.0.3", |
54 | "lexik/form-filter-bundle": "~4.0", | 54 | "lexik/form-filter-bundle": "~4.0", |
55 | "j0k3r/graby": "~1.0", | 55 | "j0k3r/graby": "~1.0", |
56 | "friendsofsymfony/user-bundle": "dev-master" | 56 | "friendsofsymfony/user-bundle": "dev-master", |
57 | "friendsofsymfony/oauth-server-bundle": "^1.4@dev" | ||
57 | }, | 58 | }, |
58 | "require-dev": { | 59 | "require-dev": { |
59 | "doctrine/doctrine-fixtures-bundle": "~2.2.0", | 60 | "doctrine/doctrine-fixtures-bundle": "~2.2.0", |
diff --git a/composer.lock b/composer.lock index 370d8ddd..606c3678 100644 --- a/composer.lock +++ b/composer.lock | |||
@@ -1,10 +1,10 @@ | |||
1 | { | 1 | { |
2 | "_readme": [ | 2 | "_readme": [ |
3 | "This file locks the dependencies of your project to a known state", | 3 | "This file locks the dependencies of your project to a known state", |
4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", | 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", |
5 | "This file is @generated automatically" | 5 | "This file is @generated automatically" |
6 | ], | 6 | ], |
7 | "hash": "350d05d95be50b6d93e8a046f784e00c", | 7 | "hash": "7c1f2c88df608eb6e1b4bc7c5ed24acc", |
8 | "packages": [ | 8 | "packages": [ |
9 | { | 9 | { |
10 | "name": "doctrine/annotations", | 10 | "name": "doctrine/annotations", |
@@ -859,6 +859,129 @@ | |||
859 | "time": "2014-05-20 12:10:12" | 859 | "time": "2014-05-20 12:10:12" |
860 | }, | 860 | }, |
861 | { | 861 | { |
862 | "name": "friendsofsymfony/oauth-server-bundle", | ||
863 | "version": "1.4.2", | ||
864 | "target-dir": "FOS/OAuthServerBundle", | ||
865 | "source": { | ||
866 | "type": "git", | ||
867 | "url": "https://github.com/FriendsOfSymfony/FOSOAuthServerBundle.git", | ||
868 | "reference": "9e15c229eff547443d686445d629e9356ab0672e" | ||
869 | }, | ||
870 | "dist": { | ||
871 | "type": "zip", | ||
872 | "url": "https://api.github.com/repos/FriendsOfSymfony/FOSOAuthServerBundle/zipball/9e15c229eff547443d686445d629e9356ab0672e", | ||
873 | "reference": "9e15c229eff547443d686445d629e9356ab0672e", | ||
874 | "shasum": "" | ||
875 | }, | ||
876 | "require": { | ||
877 | "friendsofsymfony/oauth2-php": "~1.1.0", | ||
878 | "php": ">=5.3.3", | ||
879 | "symfony/framework-bundle": "~2.1", | ||
880 | "symfony/security-bundle": "~2.1" | ||
881 | }, | ||
882 | "require-dev": { | ||
883 | "doctrine/doctrine-bundle": "~1.0", | ||
884 | "doctrine/mongodb-odm": "1.0.*@dev", | ||
885 | "doctrine/orm": ">=2.2,<2.5-dev", | ||
886 | "symfony/class-loader": "~2.1", | ||
887 | "symfony/yaml": "~2.1", | ||
888 | "willdurand/propel-typehintable-behavior": "1.0.*" | ||
889 | }, | ||
890 | "suggest": { | ||
891 | "doctrine/doctrine-bundle": "*", | ||
892 | "doctrine/mongodb-odm-bundle": "*", | ||
893 | "propel/propel-bundle": "If you want to use Propel with Symfony2, then you will have to install the PropelBundle", | ||
894 | "willdurand/propel-typehintable-behavior": "The Typehintable behavior is useful to add type hints on generated methods, to be compliant with interfaces" | ||
895 | }, | ||
896 | "type": "symfony-bundle", | ||
897 | "extra": { | ||
898 | "branch-alias": { | ||
899 | "dev-master": "1.4-dev" | ||
900 | } | ||
901 | }, | ||
902 | "autoload": { | ||
903 | "psr-0": { | ||
904 | "FOS\\OAuthServerBundle": "" | ||
905 | } | ||
906 | }, | ||
907 | "notification-url": "https://packagist.org/downloads/", | ||
908 | "license": [ | ||
909 | "MIT" | ||
910 | ], | ||
911 | "authors": [ | ||
912 | { | ||
913 | "name": "Arnaud Le Blanc", | ||
914 | "email": "arnaud.lb@gmail.com" | ||
915 | }, | ||
916 | { | ||
917 | "name": "FriendsOfSymfony Community", | ||
918 | "homepage": "https://github.com/FriendsOfSymfony/FOSOAuthServerBundle/contributors" | ||
919 | } | ||
920 | ], | ||
921 | "description": "Symfony2 OAuth Server Bundle", | ||
922 | "homepage": "http://friendsofsymfony.github.com", | ||
923 | "keywords": [ | ||
924 | "oauth", | ||
925 | "oauth2", | ||
926 | "server" | ||
927 | ], | ||
928 | "time": "2014-10-31 13:44:14" | ||
929 | }, | ||
930 | { | ||
931 | "name": "friendsofsymfony/oauth2-php", | ||
932 | "version": "1.1.1", | ||
933 | "source": { | ||
934 | "type": "git", | ||
935 | "url": "https://github.com/FriendsOfSymfony/oauth2-php.git", | ||
936 | "reference": "23e76537c4a02e666ab4ba5abe67a69a886a0310" | ||
937 | }, | ||
938 | "dist": { | ||
939 | "type": "zip", | ||
940 | "url": "https://api.github.com/repos/FriendsOfSymfony/oauth2-php/zipball/23e76537c4a02e666ab4ba5abe67a69a886a0310", | ||
941 | "reference": "23e76537c4a02e666ab4ba5abe67a69a886a0310", | ||
942 | "shasum": "" | ||
943 | }, | ||
944 | "require": { | ||
945 | "php": ">=5.3.2", | ||
946 | "symfony/http-foundation": "~2.0" | ||
947 | }, | ||
948 | "require-dev": { | ||
949 | "phpunit/phpunit": "~4.0" | ||
950 | }, | ||
951 | "type": "library", | ||
952 | "extra": { | ||
953 | "branch-alias": { | ||
954 | "dev-master": "1.1.x-dev" | ||
955 | } | ||
956 | }, | ||
957 | "autoload": { | ||
958 | "psr-4": { | ||
959 | "OAuth2\\": "lib/" | ||
960 | } | ||
961 | }, | ||
962 | "notification-url": "https://packagist.org/downloads/", | ||
963 | "license": [ | ||
964 | "MIT" | ||
965 | ], | ||
966 | "authors": [ | ||
967 | { | ||
968 | "name": "Arnaud Le Blanc", | ||
969 | "email": "arnaud.lb@gmail.com" | ||
970 | }, | ||
971 | { | ||
972 | "name": "FriendsOfSymfony Community", | ||
973 | "homepage": "https://github.com/FriendsOfSymfony/oauth2-php/contributors" | ||
974 | } | ||
975 | ], | ||
976 | "description": "OAuth2 library", | ||
977 | "homepage": "https://github.com/FriendsOfSymfony/oauth2-php", | ||
978 | "keywords": [ | ||
979 | "oauth", | ||
980 | "oauth2" | ||
981 | ], | ||
982 | "time": "2014-11-03 10:21:20" | ||
983 | }, | ||
984 | { | ||
862 | "name": "friendsofsymfony/rest-bundle", | 985 | "name": "friendsofsymfony/rest-bundle", |
863 | "version": "1.7.1", | 986 | "version": "1.7.1", |
864 | "target-dir": "FOS/RestBundle", | 987 | "target-dir": "FOS/RestBundle", |
@@ -2787,12 +2910,12 @@ | |||
2787 | "version": "v2.7.0", | 2910 | "version": "v2.7.0", |
2788 | "source": { | 2911 | "source": { |
2789 | "type": "git", | 2912 | "type": "git", |
2790 | "url": "https://github.com/symfony/AsseticBundle.git", | 2913 | "url": "https://github.com/symfony/assetic-bundle.git", |
2791 | "reference": "3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5" | 2914 | "reference": "3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5" |
2792 | }, | 2915 | }, |
2793 | "dist": { | 2916 | "dist": { |
2794 | "type": "zip", | 2917 | "type": "zip", |
2795 | "url": "https://api.github.com/repos/symfony/AsseticBundle/zipball/3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5", | 2918 | "url": "https://api.github.com/repos/symfony/assetic-bundle/zipball/3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5", |
2796 | "reference": "3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5", | 2919 | "reference": "3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5", |
2797 | "shasum": "" | 2920 | "shasum": "" |
2798 | }, | 2921 | }, |
@@ -2857,12 +2980,12 @@ | |||
2857 | "version": "v2.7.1", | 2980 | "version": "v2.7.1", |
2858 | "source": { | 2981 | "source": { |
2859 | "type": "git", | 2982 | "type": "git", |
2860 | "url": "https://github.com/symfony/MonologBundle.git", | 2983 | "url": "https://github.com/symfony/monolog-bundle.git", |
2861 | "reference": "9320b6863404c70ebe111e9040dab96f251de7ac" | 2984 | "reference": "9320b6863404c70ebe111e9040dab96f251de7ac" |
2862 | }, | 2985 | }, |
2863 | "dist": { | 2986 | "dist": { |
2864 | "type": "zip", | 2987 | "type": "zip", |
2865 | "url": "https://api.github.com/repos/symfony/MonologBundle/zipball/9320b6863404c70ebe111e9040dab96f251de7ac", | 2988 | "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/9320b6863404c70ebe111e9040dab96f251de7ac", |
2866 | "reference": "9320b6863404c70ebe111e9040dab96f251de7ac", | 2989 | "reference": "9320b6863404c70ebe111e9040dab96f251de7ac", |
2867 | "shasum": "" | 2990 | "shasum": "" |
2868 | }, | 2991 | }, |
@@ -2916,12 +3039,12 @@ | |||
2916 | "version": "v2.3.8", | 3039 | "version": "v2.3.8", |
2917 | "source": { | 3040 | "source": { |
2918 | "type": "git", | 3041 | "type": "git", |
2919 | "url": "https://github.com/symfony/SwiftmailerBundle.git", | 3042 | "url": "https://github.com/symfony/swiftmailer-bundle.git", |
2920 | "reference": "970b13d01871207e81d17b17ddda025e7e21e797" | 3043 | "reference": "970b13d01871207e81d17b17ddda025e7e21e797" |
2921 | }, | 3044 | }, |
2922 | "dist": { | 3045 | "dist": { |
2923 | "type": "zip", | 3046 | "type": "zip", |
2924 | "url": "https://api.github.com/repos/symfony/SwiftmailerBundle/zipball/970b13d01871207e81d17b17ddda025e7e21e797", | 3047 | "url": "https://api.github.com/repos/symfony/swiftmailer-bundle/zipball/970b13d01871207e81d17b17ddda025e7e21e797", |
2925 | "reference": "970b13d01871207e81d17b17ddda025e7e21e797", | 3048 | "reference": "970b13d01871207e81d17b17ddda025e7e21e797", |
2926 | "shasum": "" | 3049 | "shasum": "" |
2927 | }, | 3050 | }, |
@@ -2970,20 +3093,20 @@ | |||
2970 | }, | 3093 | }, |
2971 | { | 3094 | { |
2972 | "name": "symfony/symfony", | 3095 | "name": "symfony/symfony", |
2973 | "version": "v2.7.5", | 3096 | "version": "v2.7.4", |
2974 | "source": { | 3097 | "source": { |
2975 | "type": "git", | 3098 | "type": "git", |
2976 | "url": "https://github.com/symfony/symfony.git", | 3099 | "url": "https://github.com/symfony/symfony.git", |
2977 | "reference": "619528a274647cffc1792063c3ea04c4fa8266a0" | 3100 | "reference": "1fdf23fe28876844b887b0e1935c9adda43ee645" |
2978 | }, | 3101 | }, |
2979 | "dist": { | 3102 | "dist": { |
2980 | "type": "zip", | 3103 | "type": "zip", |
2981 | "url": "https://api.github.com/repos/symfony/symfony/zipball/619528a274647cffc1792063c3ea04c4fa8266a0", | 3104 | "url": "https://api.github.com/repos/symfony/symfony/zipball/1fdf23fe28876844b887b0e1935c9adda43ee645", |
2982 | "reference": "619528a274647cffc1792063c3ea04c4fa8266a0", | 3105 | "reference": "1fdf23fe28876844b887b0e1935c9adda43ee645", |
2983 | "shasum": "" | 3106 | "shasum": "" |
2984 | }, | 3107 | }, |
2985 | "require": { | 3108 | "require": { |
2986 | "doctrine/common": "~2.4", | 3109 | "doctrine/common": "~2.3", |
2987 | "php": ">=5.3.9", | 3110 | "php": ">=5.3.9", |
2988 | "psr/log": "~1.0", | 3111 | "psr/log": "~1.0", |
2989 | "twig/twig": "~1.20|~2.0" | 3112 | "twig/twig": "~1.20|~2.0" |
@@ -3036,9 +3159,9 @@ | |||
3036 | }, | 3159 | }, |
3037 | "require-dev": { | 3160 | "require-dev": { |
3038 | "doctrine/data-fixtures": "1.0.*", | 3161 | "doctrine/data-fixtures": "1.0.*", |
3039 | "doctrine/dbal": "~2.4", | 3162 | "doctrine/dbal": "~2.2", |
3040 | "doctrine/doctrine-bundle": "~1.2", | 3163 | "doctrine/doctrine-bundle": "~1.2", |
3041 | "doctrine/orm": "~2.4,>=2.4.5", | 3164 | "doctrine/orm": "~2.2,>=2.2.3", |
3042 | "egulias/email-validator": "~1.2", | 3165 | "egulias/email-validator": "~1.2", |
3043 | "ircmaxell/password-compat": "~1.0", | 3166 | "ircmaxell/password-compat": "~1.0", |
3044 | "monolog/monolog": "~1.11", | 3167 | "monolog/monolog": "~1.11", |
@@ -3088,7 +3211,7 @@ | |||
3088 | "keywords": [ | 3211 | "keywords": [ |
3089 | "framework" | 3212 | "framework" |
3090 | ], | 3213 | ], |
3091 | "time": "2015-09-25 11:16:52" | 3214 | "time": "2015-09-08 14:26:39" |
3092 | }, | 3215 | }, |
3093 | { | 3216 | { |
3094 | "name": "tecnickcom/tcpdf", | 3217 | "name": "tecnickcom/tcpdf", |
@@ -4488,7 +4611,8 @@ | |||
4488 | "aliases": [], | 4611 | "aliases": [], |
4489 | "minimum-stability": "dev", | 4612 | "minimum-stability": "dev", |
4490 | "stability-flags": { | 4613 | "stability-flags": { |
4491 | "friendsofsymfony/user-bundle": 20 | 4614 | "friendsofsymfony/user-bundle": 20, |
4615 | "friendsofsymfony/oauth-server-bundle": 20 | ||
4492 | }, | 4616 | }, |
4493 | "prefer-stable": true, | 4617 | "prefer-stable": true, |
4494 | "prefer-lowest": false, | 4618 | "prefer-lowest": false, |
diff --git a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php index 349229f3..284dbb25 100644 --- a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php +++ b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php | |||
@@ -2,8 +2,8 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\ApiBundle\Controller; | 3 | namespace Wallabag\ApiBundle\Controller; |
4 | 4 | ||
5 | use FOS\RestBundle\Controller\FOSRestController; | ||
5 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; | 6 | use Nelmio\ApiDocBundle\Annotation\ApiDoc; |
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | ||
7 | use Symfony\Component\HttpFoundation\Request; | 7 | use Symfony\Component\HttpFoundation\Request; |
8 | use Symfony\Component\HttpFoundation\Response; | 8 | use Symfony\Component\HttpFoundation\Response; |
9 | use Wallabag\CoreBundle\Entity\Entry; | 9 | use Wallabag\CoreBundle\Entity\Entry; |
@@ -11,7 +11,7 @@ use Wallabag\CoreBundle\Entity\Tag; | |||
11 | use Hateoas\Configuration\Route; | 11 | use Hateoas\Configuration\Route; |
12 | use Hateoas\Representation\Factory\PagerfantaFactory; | 12 | use Hateoas\Representation\Factory\PagerfantaFactory; |
13 | 13 | ||
14 | class WallabagRestController extends Controller | 14 | class WallabagRestController extends FOSRestController |
15 | { | 15 | { |
16 | /** | 16 | /** |
17 | * @param Entry $entry | 17 | * @param Entry $entry |
@@ -39,31 +39,6 @@ class WallabagRestController extends Controller | |||
39 | } | 39 | } |
40 | 40 | ||
41 | /** | 41 | /** |
42 | * Retrieve salt for a giver user. | ||
43 | * | ||
44 | * @ApiDoc( | ||
45 | * parameters={ | ||
46 | * {"name"="username", "dataType"="string", "required"=true, "description"="username"} | ||
47 | * } | ||
48 | * ) | ||
49 | * | ||
50 | * @return array | ||
51 | */ | ||
52 | public function getSaltAction($username) | ||
53 | { | ||
54 | $user = $this | ||
55 | ->getDoctrine() | ||
56 | ->getRepository('WallabagCoreBundle:User') | ||
57 | ->findOneByUsername($username); | ||
58 | |||
59 | if (is_null($user)) { | ||
60 | throw $this->createNotFoundException(); | ||
61 | } | ||
62 | |||
63 | return array($user->getSalt() ?: null); | ||
64 | } | ||
65 | |||
66 | /** | ||
67 | * Retrieve all entries. It could be filtered by many options. | 42 | * Retrieve all entries. It could be filtered by many options. |
68 | * | 43 | * |
69 | * @ApiDoc( | 44 | * @ApiDoc( |
@@ -122,7 +97,7 @@ class WallabagRestController extends Controller | |||
122 | */ | 97 | */ |
123 | public function getEntryAction(Entry $entry) | 98 | public function getEntryAction(Entry $entry) |
124 | { | 99 | { |
125 | $this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId()); | 100 | $this->validateUserAccess($entry->getUser()->getId()); |
126 | 101 | ||
127 | $json = $this->get('serializer')->serialize($entry, 'json'); | 102 | $json = $this->get('serializer')->serialize($entry, 'json'); |
128 | 103 | ||
@@ -184,7 +159,7 @@ class WallabagRestController extends Controller | |||
184 | */ | 159 | */ |
185 | public function patchEntriesAction(Entry $entry, Request $request) | 160 | public function patchEntriesAction(Entry $entry, Request $request) |
186 | { | 161 | { |
187 | $this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId()); | 162 | $this->validateUserAccess($entry->getUser()->getId()); |
188 | 163 | ||
189 | $title = $request->request->get('title'); | 164 | $title = $request->request->get('title'); |
190 | $isArchived = $request->request->get('is_archived'); | 165 | $isArchived = $request->request->get('is_archived'); |
@@ -228,7 +203,7 @@ class WallabagRestController extends Controller | |||
228 | */ | 203 | */ |
229 | public function deleteEntriesAction(Entry $entry) | 204 | public function deleteEntriesAction(Entry $entry) |
230 | { | 205 | { |
231 | $this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId()); | 206 | $this->validateUserAccess($entry->getUser()->getId()); |
232 | 207 | ||
233 | $em = $this->getDoctrine()->getManager(); | 208 | $em = $this->getDoctrine()->getManager(); |
234 | $em->remove($entry); | 209 | $em->remove($entry); |
@@ -250,7 +225,7 @@ class WallabagRestController extends Controller | |||
250 | */ | 225 | */ |
251 | public function getEntriesTagsAction(Entry $entry) | 226 | public function getEntriesTagsAction(Entry $entry) |
252 | { | 227 | { |
253 | $this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId()); | 228 | $this->validateUserAccess($entry->getUser()->getId()); |
254 | 229 | ||
255 | $json = $this->get('serializer')->serialize($entry->getTags(), 'json'); | 230 | $json = $this->get('serializer')->serialize($entry->getTags(), 'json'); |
256 | 231 | ||
@@ -271,7 +246,7 @@ class WallabagRestController extends Controller | |||
271 | */ | 246 | */ |
272 | public function postEntriesTagsAction(Request $request, Entry $entry) | 247 | public function postEntriesTagsAction(Request $request, Entry $entry) |
273 | { | 248 | { |
274 | $this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId()); | 249 | $this->validateUserAccess($entry->getUser()->getId()); |
275 | 250 | ||
276 | $tags = $request->request->get('tags', ''); | 251 | $tags = $request->request->get('tags', ''); |
277 | if (!empty($tags)) { | 252 | if (!empty($tags)) { |
@@ -299,7 +274,7 @@ class WallabagRestController extends Controller | |||
299 | */ | 274 | */ |
300 | public function deleteEntriesTagsAction(Entry $entry, Tag $tag) | 275 | public function deleteEntriesTagsAction(Entry $entry, Tag $tag) |
301 | { | 276 | { |
302 | $this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId()); | 277 | $this->validateUserAccess($entry->getUser()->getId()); |
303 | 278 | ||
304 | $entry->removeTag($tag); | 279 | $entry->removeTag($tag); |
305 | $em = $this->getDoctrine()->getManager(); | 280 | $em = $this->getDoctrine()->getManager(); |
@@ -334,7 +309,7 @@ class WallabagRestController extends Controller | |||
334 | */ | 309 | */ |
335 | public function deleteTagAction(Tag $tag) | 310 | public function deleteTagAction(Tag $tag) |
336 | { | 311 | { |
337 | $this->validateUserAccess($tag->getUser()->getId(), $this->getUser()->getId()); | 312 | $this->validateUserAccess($tag->getUser()->getId()); |
338 | 313 | ||
339 | $em = $this->getDoctrine()->getManager(); | 314 | $em = $this->getDoctrine()->getManager(); |
340 | $em->remove($tag); | 315 | $em->remove($tag); |
@@ -350,12 +325,12 @@ class WallabagRestController extends Controller | |||
350 | * If not, throw exception. It means a user try to access information from an other user. | 325 | * If not, throw exception. It means a user try to access information from an other user. |
351 | * | 326 | * |
352 | * @param int $requestUserId User id from the requested source | 327 | * @param int $requestUserId User id from the requested source |
353 | * @param int $currentUserId User id from the retrieved source | ||
354 | */ | 328 | */ |
355 | private function validateUserAccess($requestUserId, $currentUserId) | 329 | private function validateUserAccess($requestUserId) |
356 | { | 330 | { |
357 | if ($requestUserId != $currentUserId) { | 331 | $user = $this->get('security.context')->getToken()->getUser(); |
358 | throw $this->createAccessDeniedException('Access forbidden. Entry user id: '.$requestUserId.', logged user id: '.$currentUserId); | 332 | if ($requestUserId != $user->getId()) { |
333 | throw $this->createAccessDeniedException('Access forbidden. Entry user id: '.$requestUserId.', logged user id: '.$user->getId()); | ||
359 | } | 334 | } |
360 | } | 335 | } |
361 | 336 | ||
diff --git a/src/Wallabag/ApiBundle/DependencyInjection/Security/Factory/WsseFactory.php b/src/Wallabag/ApiBundle/DependencyInjection/Security/Factory/WsseFactory.php deleted file mode 100644 index 402eb869..00000000 --- a/src/Wallabag/ApiBundle/DependencyInjection/Security/Factory/WsseFactory.php +++ /dev/null | |||
@@ -1,40 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\DependencyInjection\Security\Factory; | ||
4 | |||
5 | use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
6 | use Symfony\Component\DependencyInjection\Reference; | ||
7 | use Symfony\Component\DependencyInjection\DefinitionDecorator; | ||
8 | use Symfony\Component\Config\Definition\Builder\NodeDefinition; | ||
9 | use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; | ||
10 | |||
11 | class WsseFactory implements SecurityFactoryInterface | ||
12 | { | ||
13 | public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint) | ||
14 | { | ||
15 | $providerId = 'security.authentication.provider.wsse.'.$id; | ||
16 | $container | ||
17 | ->setDefinition($providerId, new DefinitionDecorator('wsse.security.authentication.provider')) | ||
18 | ->replaceArgument(0, new Reference($userProvider)) | ||
19 | ; | ||
20 | |||
21 | $listenerId = 'security.authentication.listener.wsse.'.$id; | ||
22 | $listener = $container->setDefinition($listenerId, new DefinitionDecorator('wsse.security.authentication.listener')); | ||
23 | |||
24 | return array($providerId, $listenerId, $defaultEntryPoint); | ||
25 | } | ||
26 | |||
27 | public function getPosition() | ||
28 | { | ||
29 | return 'pre_auth'; | ||
30 | } | ||
31 | |||
32 | public function getKey() | ||
33 | { | ||
34 | return 'wsse'; | ||
35 | } | ||
36 | |||
37 | public function addConfiguration(NodeDefinition $node) | ||
38 | { | ||
39 | } | ||
40 | } | ||
diff --git a/src/Wallabag/ApiBundle/DependencyInjection/WallabagApiExtension.php b/src/Wallabag/ApiBundle/DependencyInjection/WallabagApiExtension.php index c5cc204e..a147e7ef 100644 --- a/src/Wallabag/ApiBundle/DependencyInjection/WallabagApiExtension.php +++ b/src/Wallabag/ApiBundle/DependencyInjection/WallabagApiExtension.php | |||
@@ -13,9 +13,6 @@ class WallabagApiExtension extends Extension | |||
13 | { | 13 | { |
14 | $configuration = new Configuration(); | 14 | $configuration = new Configuration(); |
15 | $config = $this->processConfiguration($configuration, $configs); | 15 | $config = $this->processConfiguration($configuration, $configs); |
16 | |||
17 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); | ||
18 | $loader->load('services.yml'); | ||
19 | } | 16 | } |
20 | 17 | ||
21 | public function getAlias() | 18 | public function getAlias() |
diff --git a/src/Wallabag/ApiBundle/Entity/AccessToken.php b/src/Wallabag/ApiBundle/Entity/AccessToken.php new file mode 100644 index 00000000..d6cf0af5 --- /dev/null +++ b/src/Wallabag/ApiBundle/Entity/AccessToken.php | |||
@@ -0,0 +1,31 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Entity; | ||
4 | |||
5 | use FOS\OAuthServerBundle\Entity\AccessToken as BaseAccessToken; | ||
6 | use Doctrine\ORM\Mapping as ORM; | ||
7 | |||
8 | /** | ||
9 | * @ORM\Table("oauth2_access_tokens") | ||
10 | * @ORM\Entity | ||
11 | */ | ||
12 | class AccessToken extends BaseAccessToken | ||
13 | { | ||
14 | /** | ||
15 | * @ORM\Id | ||
16 | * @ORM\Column(type="integer") | ||
17 | * @ORM\GeneratedValue(strategy="AUTO") | ||
18 | */ | ||
19 | protected $id; | ||
20 | |||
21 | /** | ||
22 | * @ORM\ManyToOne(targetEntity="Client") | ||
23 | * @ORM\JoinColumn(nullable=false) | ||
24 | */ | ||
25 | protected $client; | ||
26 | |||
27 | /** | ||
28 | * @ORM\ManyToOne(targetEntity="Wallabag\CoreBundle\Entity\User") | ||
29 | */ | ||
30 | protected $user; | ||
31 | } | ||
diff --git a/src/Wallabag/ApiBundle/Entity/AuthCode.php b/src/Wallabag/ApiBundle/Entity/AuthCode.php new file mode 100644 index 00000000..7873d97d --- /dev/null +++ b/src/Wallabag/ApiBundle/Entity/AuthCode.php | |||
@@ -0,0 +1,31 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Entity; | ||
4 | |||
5 | use FOS\OAuthServerBundle\Entity\AuthCode as BaseAuthCode; | ||
6 | use Doctrine\ORM\Mapping as ORM; | ||
7 | |||
8 | /** | ||
9 | * @ORM\Table("oauth2_auth_codes") | ||
10 | * @ORM\Entity | ||
11 | */ | ||
12 | class AuthCode extends BaseAuthCode | ||
13 | { | ||
14 | /** | ||
15 | * @ORM\Id | ||
16 | * @ORM\Column(type="integer") | ||
17 | * @ORM\GeneratedValue(strategy="AUTO") | ||
18 | */ | ||
19 | protected $id; | ||
20 | |||
21 | /** | ||
22 | * @ORM\ManyToOne(targetEntity="Client") | ||
23 | * @ORM\JoinColumn(nullable=false) | ||
24 | */ | ||
25 | protected $client; | ||
26 | |||
27 | /** | ||
28 | * @ORM\ManyToOne(targetEntity="Wallabag\CoreBundle\Entity\User") | ||
29 | */ | ||
30 | protected $user; | ||
31 | } | ||
diff --git a/src/Wallabag/ApiBundle/Entity/Client.php b/src/Wallabag/ApiBundle/Entity/Client.php new file mode 100644 index 00000000..d449870a --- /dev/null +++ b/src/Wallabag/ApiBundle/Entity/Client.php | |||
@@ -0,0 +1,25 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Entity; | ||
4 | |||
5 | use FOS\OAuthServerBundle\Entity\Client as BaseClient; | ||
6 | use Doctrine\ORM\Mapping as ORM; | ||
7 | |||
8 | /** | ||
9 | * @ORM\Table("oauth2_clients") | ||
10 | * @ORM\Entity | ||
11 | */ | ||
12 | class Client extends BaseClient | ||
13 | { | ||
14 | /** | ||
15 | * @ORM\Id | ||
16 | * @ORM\Column(type="integer") | ||
17 | * @ORM\GeneratedValue(strategy="AUTO") | ||
18 | */ | ||
19 | protected $id; | ||
20 | |||
21 | public function __construct() | ||
22 | { | ||
23 | parent::__construct(); | ||
24 | } | ||
25 | } | ||
diff --git a/src/Wallabag/ApiBundle/Entity/RefreshToken.php b/src/Wallabag/ApiBundle/Entity/RefreshToken.php new file mode 100644 index 00000000..74c564b7 --- /dev/null +++ b/src/Wallabag/ApiBundle/Entity/RefreshToken.php | |||
@@ -0,0 +1,31 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Entity; | ||
4 | |||
5 | use FOS\OAuthServerBundle\Entity\RefreshToken as BaseRefreshToken; | ||
6 | use Doctrine\ORM\Mapping as ORM; | ||
7 | |||
8 | /** | ||
9 | * @ORM\Table("oauth2_refresh_tokens") | ||
10 | * @ORM\Entity | ||
11 | */ | ||
12 | class RefreshToken extends BaseRefreshToken | ||
13 | { | ||
14 | /** | ||
15 | * @ORM\Id | ||
16 | * @ORM\Column(type="integer") | ||
17 | * @ORM\GeneratedValue(strategy="AUTO") | ||
18 | */ | ||
19 | protected $id; | ||
20 | |||
21 | /** | ||
22 | * @ORM\ManyToOne(targetEntity="Client") | ||
23 | * @ORM\JoinColumn(nullable=false) | ||
24 | */ | ||
25 | protected $client; | ||
26 | |||
27 | /** | ||
28 | * @ORM\ManyToOne(targetEntity="Wallabag\CoreBundle\Entity\User") | ||
29 | */ | ||
30 | protected $user; | ||
31 | } | ||
diff --git a/src/Wallabag/ApiBundle/Resources/config/services.yml b/src/Wallabag/ApiBundle/Resources/config/services.yml deleted file mode 100644 index 6854a444..00000000 --- a/src/Wallabag/ApiBundle/Resources/config/services.yml +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | services: | ||
2 | wsse.security.authentication.provider: | ||
3 | class: Wallabag\ApiBundle\Security\Authentication\Provider\WsseProvider | ||
4 | public: false | ||
5 | arguments: ['', '%kernel.cache_dir%/security/nonces'] | ||
6 | |||
7 | wsse.security.authentication.listener: | ||
8 | class: Wallabag\ApiBundle\Security\Firewall\WsseListener | ||
9 | public: false | ||
10 | tags: | ||
11 | - { name: monolog.logger, channel: wsse } | ||
12 | arguments: ['@security.context', '@security.authentication.manager', '@logger'] | ||
diff --git a/src/Wallabag/ApiBundle/Security/Authentication/Provider/WsseProvider.php b/src/Wallabag/ApiBundle/Security/Authentication/Provider/WsseProvider.php deleted file mode 100644 index 9bf8b377..00000000 --- a/src/Wallabag/ApiBundle/Security/Authentication/Provider/WsseProvider.php +++ /dev/null | |||
@@ -1,79 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Security\Authentication\Provider; | ||
4 | |||
5 | use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; | ||
6 | use Symfony\Component\Security\Core\User\UserProviderInterface; | ||
7 | use Symfony\Component\Security\Core\Exception\AuthenticationException; | ||
8 | use Symfony\Component\Security\Core\Exception\NonceExpiredException; | ||
9 | use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | ||
10 | use Wallabag\ApiBundle\Security\Authentication\Token\WsseUserToken; | ||
11 | |||
12 | class WsseProvider implements AuthenticationProviderInterface | ||
13 | { | ||
14 | private $userProvider; | ||
15 | private $cacheDir; | ||
16 | |||
17 | public function __construct(UserProviderInterface $userProvider, $cacheDir) | ||
18 | { | ||
19 | $this->userProvider = $userProvider; | ||
20 | $this->cacheDir = $cacheDir; | ||
21 | |||
22 | // If cache directory does not exist we create it | ||
23 | if (!is_dir($this->cacheDir)) { | ||
24 | mkdir($this->cacheDir, 0777, true); | ||
25 | } | ||
26 | } | ||
27 | |||
28 | public function authenticate(TokenInterface $token) | ||
29 | { | ||
30 | $user = $this->userProvider->loadUserByUsername($token->getUsername()); | ||
31 | |||
32 | if (!$user) { | ||
33 | throw new AuthenticationException('Bad credentials. Did you forgot your username?'); | ||
34 | } | ||
35 | |||
36 | if ($user && $this->validateDigest($token->digest, $token->nonce, $token->created, $user->getPassword())) { | ||
37 | $authenticatedToken = new WsseUserToken($user->getRoles()); | ||
38 | $authenticatedToken->setUser($user); | ||
39 | |||
40 | return $authenticatedToken; | ||
41 | } | ||
42 | |||
43 | throw new AuthenticationException('The WSSE authentication failed.'); | ||
44 | } | ||
45 | |||
46 | protected function validateDigest($digest, $nonce, $created, $secret) | ||
47 | { | ||
48 | // Check created time is not in the future | ||
49 | if (strtotime($created) > time()) { | ||
50 | throw new AuthenticationException('Back to the future...'); | ||
51 | } | ||
52 | |||
53 | // Expire timestamp after 5 minutes | ||
54 | if (time() - strtotime($created) > 300) { | ||
55 | throw new AuthenticationException('Too late for this timestamp... Watch your watch.'); | ||
56 | } | ||
57 | |||
58 | // Validate nonce is unique within 5 minutes | ||
59 | if (file_exists($this->cacheDir.'/'.$nonce) && file_get_contents($this->cacheDir.'/'.$nonce) + 300 > time()) { | ||
60 | throw new NonceExpiredException('Previously used nonce detected'); | ||
61 | } | ||
62 | |||
63 | file_put_contents($this->cacheDir.'/'.$nonce, time()); | ||
64 | |||
65 | // Validate Secret | ||
66 | $expected = base64_encode(sha1(base64_decode($nonce).$created.$secret, true)); | ||
67 | |||
68 | if ($digest !== $expected) { | ||
69 | throw new AuthenticationException('Bad credentials ! Digest is not as expected.'); | ||
70 | } | ||
71 | |||
72 | return $digest === $expected; | ||
73 | } | ||
74 | |||
75 | public function supports(TokenInterface $token) | ||
76 | { | ||
77 | return $token instanceof WsseUserToken; | ||
78 | } | ||
79 | } | ||
diff --git a/src/Wallabag/ApiBundle/Security/Authentication/Token/WsseUserToken.php b/src/Wallabag/ApiBundle/Security/Authentication/Token/WsseUserToken.php deleted file mode 100644 index e6d30224..00000000 --- a/src/Wallabag/ApiBundle/Security/Authentication/Token/WsseUserToken.php +++ /dev/null | |||
@@ -1,24 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Security\Authentication\Token; | ||
4 | |||
5 | use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; | ||
6 | |||
7 | class WsseUserToken extends AbstractToken | ||
8 | { | ||
9 | public $created; | ||
10 | public $digest; | ||
11 | public $nonce; | ||
12 | |||
13 | public function __construct(array $roles = array()) | ||
14 | { | ||
15 | parent::__construct($roles); | ||
16 | |||
17 | $this->setAuthenticated(count($roles) > 0); | ||
18 | } | ||
19 | |||
20 | public function getCredentials() | ||
21 | { | ||
22 | return ''; | ||
23 | } | ||
24 | } | ||
diff --git a/src/Wallabag/ApiBundle/Security/Firewall/WsseListener.php b/src/Wallabag/ApiBundle/Security/Firewall/WsseListener.php deleted file mode 100644 index 2fcbe014..00000000 --- a/src/Wallabag/ApiBundle/Security/Firewall/WsseListener.php +++ /dev/null | |||
@@ -1,62 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Security\Firewall; | ||
4 | |||
5 | use Symfony\Component\HttpFoundation\Response; | ||
6 | use Symfony\Component\HttpKernel\Event\GetResponseEvent; | ||
7 | use Symfony\Component\Security\Http\Firewall\ListenerInterface; | ||
8 | use Symfony\Component\Security\Core\Exception\AuthenticationException; | ||
9 | use Symfony\Component\Security\Core\SecurityContextInterface; | ||
10 | use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; | ||
11 | use Wallabag\ApiBundle\Security\Authentication\Token\WsseUserToken; | ||
12 | use Psr\Log\LoggerInterface; | ||
13 | |||
14 | class WsseListener implements ListenerInterface | ||
15 | { | ||
16 | protected $securityContext; | ||
17 | protected $authenticationManager; | ||
18 | protected $logger; | ||
19 | |||
20 | public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger) | ||
21 | { | ||
22 | $this->securityContext = $securityContext; | ||
23 | $this->authenticationManager = $authenticationManager; | ||
24 | $this->logger = $logger; | ||
25 | } | ||
26 | |||
27 | public function handle(GetResponseEvent $event) | ||
28 | { | ||
29 | $request = $event->getRequest(); | ||
30 | |||
31 | $wsseRegex = '/UsernameToken Username="([^"]+)", PasswordDigest="([^"]+)", Nonce="([^"]+)", Created="([^"]+)"/'; | ||
32 | if (!$request->headers->has('x-wsse') || 1 !== preg_match($wsseRegex, $request->headers->get('x-wsse'), $matches)) { | ||
33 | return; | ||
34 | } | ||
35 | |||
36 | $token = new WsseUserToken(); | ||
37 | $token->setUser($matches[1]); | ||
38 | |||
39 | $token->digest = $matches[2]; | ||
40 | $token->nonce = $matches[3]; | ||
41 | $token->created = $matches[4]; | ||
42 | |||
43 | try { | ||
44 | $authToken = $this->authenticationManager->authenticate($token); | ||
45 | |||
46 | $this->securityContext->setToken($authToken); | ||
47 | |||
48 | return; | ||
49 | } catch (AuthenticationException $failed) { | ||
50 | $failedMessage = 'WSSE Login failed for '.$token->getUsername().'. Why ? '.$failed->getMessage(); | ||
51 | $this->logger->err($failedMessage); | ||
52 | |||
53 | // Deny authentication with a '403 Forbidden' HTTP response | ||
54 | $response = new Response(); | ||
55 | $response->setStatusCode(403); | ||
56 | $response->setContent($failedMessage); | ||
57 | $event->setResponse($response); | ||
58 | |||
59 | return; | ||
60 | } | ||
61 | } | ||
62 | } | ||
diff --git a/src/Wallabag/ApiBundle/Tests/AbstractControllerTest.php b/src/Wallabag/ApiBundle/Tests/AbstractControllerTest.php new file mode 100644 index 00000000..119889b3 --- /dev/null +++ b/src/Wallabag/ApiBundle/Tests/AbstractControllerTest.php | |||
@@ -0,0 +1,46 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\ApiBundle\Tests; | ||
4 | |||
5 | use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; | ||
6 | use Symfony\Component\BrowserKit\Cookie; | ||
7 | |||
8 | abstract class AbstractControllerTest extends WebTestCase | ||
9 | { | ||
10 | /** | ||
11 | * @var Client | ||
12 | */ | ||
13 | protected $client = null; | ||
14 | |||
15 | public function setUp() | ||
16 | { | ||
17 | $this->client = $this->createAuthorizedClient(); | ||
18 | } | ||
19 | |||
20 | /** | ||
21 | * @return Client | ||
22 | */ | ||
23 | protected function createAuthorizedClient() | ||
24 | { | ||
25 | $client = static::createClient(); | ||
26 | $container = $client->getContainer(); | ||
27 | |||
28 | $session = $container->get('session'); | ||
29 | /** @var $userManager \FOS\UserBundle\Doctrine\UserManager */ | ||
30 | $userManager = $container->get('fos_user.user_manager'); | ||
31 | /** @var $loginManager \FOS\UserBundle\Security\LoginManager */ | ||
32 | $loginManager = $container->get('fos_user.security.login_manager'); | ||
33 | $firewallName = $container->getParameter('fos_user.firewall_name'); | ||
34 | |||
35 | $user = $userManager->findUserBy(array('username' => 'admin')); | ||
36 | $loginManager->loginUser($firewallName, $user); | ||
37 | |||
38 | // save the login token into the session and put it in a cookie | ||
39 | $container->get('session')->set('_security_'.$firewallName, | ||
40 | serialize($container->get('security.context')->getToken())); | ||
41 | $container->get('session')->save(); | ||
42 | $client->getCookieJar()->set(new Cookie($session->getName(), $session->getId())); | ||
43 | |||
44 | return $client; | ||
45 | } | ||
46 | } | ||
diff --git a/src/Wallabag/ApiBundle/Tests/Controller/WallabagRestControllerTest.php b/src/Wallabag/ApiBundle/Tests/Controller/WallabagRestControllerTest.php index 7ae54b57..bc7ef489 100644 --- a/src/Wallabag/ApiBundle/Tests/Controller/WallabagRestControllerTest.php +++ b/src/Wallabag/ApiBundle/Tests/Controller/WallabagRestControllerTest.php | |||
@@ -2,99 +2,15 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\ApiBundle\Tests\Controller; | 3 | namespace Wallabag\ApiBundle\Tests\Controller; |
4 | 4 | ||
5 | use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; | 5 | use Wallabag\ApiBundle\Tests\AbstractControllerTest; |
6 | 6 | ||
7 | class WallabagRestControllerTest extends WebTestCase | 7 | class WallabagRestControllerTest extends AbstractControllerTest |
8 | { | 8 | { |
9 | protected static $salt; | 9 | protected static $salt; |
10 | 10 | ||
11 | /** | ||
12 | * Grab the salt once and store it to be available for all tests. | ||
13 | */ | ||
14 | public static function setUpBeforeClass() | ||
15 | { | ||
16 | $client = self::createClient(); | ||
17 | |||
18 | $user = $client->getContainer() | ||
19 | ->get('doctrine.orm.entity_manager') | ||
20 | ->getRepository('WallabagCoreBundle:User') | ||
21 | ->findOneByUsername('admin'); | ||
22 | |||
23 | self::$salt = $user->getSalt(); | ||
24 | } | ||
25 | |||
26 | /** | ||
27 | * Generate HTTP headers for authenticate user on API. | ||
28 | * | ||
29 | * @param string $username | ||
30 | * @param string $password | ||
31 | * | ||
32 | * @return array | ||
33 | */ | ||
34 | private function generateHeaders($username, $password) | ||
35 | { | ||
36 | $encryptedPassword = sha1($password.$username.self::$salt); | ||
37 | $nonce = substr(md5(uniqid('nonce_', true)), 0, 16); | ||
38 | |||
39 | $now = new \DateTime('now', new \DateTimeZone('UTC')); | ||
40 | $created = (string) $now->format('Y-m-d\TH:i:s\Z'); | ||
41 | $digest = base64_encode(sha1(base64_decode($nonce).$created.$encryptedPassword, true)); | ||
42 | |||
43 | return array( | ||
44 | 'HTTP_AUTHORIZATION' => 'Authorization profile="UsernameToken"', | ||
45 | 'HTTP_x-wsse' => 'X-WSSE: UsernameToken Username="'.$username.'", PasswordDigest="'.$digest.'", Nonce="'.$nonce.'", Created="'.$created.'"', | ||
46 | ); | ||
47 | } | ||
48 | |||
49 | public function testGetSalt() | ||
50 | { | ||
51 | $client = $this->createClient(); | ||
52 | $client->request('GET', '/api/salts/admin.json'); | ||
53 | |||
54 | $user = $client->getContainer() | ||
55 | ->get('doctrine.orm.entity_manager') | ||
56 | ->getRepository('WallabagCoreBundle:User') | ||
57 | ->findOneByUsername('admin'); | ||
58 | |||
59 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | ||
60 | |||
61 | $content = json_decode($client->getResponse()->getContent(), true); | ||
62 | |||
63 | $this->assertArrayHasKey(0, $content); | ||
64 | $this->assertEquals($user->getSalt(), $content[0]); | ||
65 | |||
66 | $client->request('GET', '/api/salts/notfound.json'); | ||
67 | $this->assertEquals(404, $client->getResponse()->getStatusCode()); | ||
68 | } | ||
69 | |||
70 | public function testWithBadHeaders() | ||
71 | { | ||
72 | $client = $this->createClient(); | ||
73 | |||
74 | $entry = $client->getContainer() | ||
75 | ->get('doctrine.orm.entity_manager') | ||
76 | ->getRepository('WallabagCoreBundle:Entry') | ||
77 | ->findOneByIsArchived(false); | ||
78 | |||
79 | if (!$entry) { | ||
80 | $this->markTestSkipped('No content found in db.'); | ||
81 | } | ||
82 | |||
83 | $badHeaders = array( | ||
84 | 'HTTP_AUTHORIZATION' => 'Authorization profile="UsernameToken"', | ||
85 | 'HTTP_x-wsse' => 'X-WSSE: UsernameToken Username="admin", PasswordDigest="Wr0ngDig3st", Nonce="n0Nc3", Created="2015-01-01T13:37:00Z"', | ||
86 | ); | ||
87 | |||
88 | $client->request('GET', '/api/entries/'.$entry->getId().'.json', array(), array(), $badHeaders); | ||
89 | $this->assertEquals(403, $client->getResponse()->getStatusCode()); | ||
90 | } | ||
91 | |||
92 | public function testGetOneEntry() | 11 | public function testGetOneEntry() |
93 | { | 12 | { |
94 | $client = $this->createClient(); | 13 | $entry = $this->client->getContainer() |
95 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
96 | |||
97 | $entry = $client->getContainer() | ||
98 | ->get('doctrine.orm.entity_manager') | 14 | ->get('doctrine.orm.entity_manager') |
99 | ->getRepository('WallabagCoreBundle:Entry') | 15 | ->getRepository('WallabagCoreBundle:Entry') |
100 | ->findOneBy(array('user' => 1, 'isArchived' => false)); | 16 | ->findOneBy(array('user' => 1, 'isArchived' => false)); |
@@ -103,18 +19,17 @@ class WallabagRestControllerTest extends WebTestCase | |||
103 | $this->markTestSkipped('No content found in db.'); | 19 | $this->markTestSkipped('No content found in db.'); |
104 | } | 20 | } |
105 | 21 | ||
106 | $client->request('GET', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers); | 22 | $this->client->request('GET', '/api/entries/'.$entry->getId().'.json'); |
23 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); | ||
107 | 24 | ||
108 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 25 | $content = json_decode($this->client->getResponse()->getContent(), true); |
109 | |||
110 | $content = json_decode($client->getResponse()->getContent(), true); | ||
111 | 26 | ||
112 | $this->assertEquals($entry->getTitle(), $content['title']); | 27 | $this->assertEquals($entry->getTitle(), $content['title']); |
113 | $this->assertEquals($entry->getUrl(), $content['url']); | 28 | $this->assertEquals($entry->getUrl(), $content['url']); |
114 | $this->assertCount(count($entry->getTags()), $content['tags']); | 29 | $this->assertCount(count($entry->getTags()), $content['tags']); |
115 | 30 | ||
116 | $this->assertTrue( | 31 | $this->assertTrue( |
117 | $client->getResponse()->headers->contains( | 32 | $this->client->getResponse()->headers->contains( |
118 | 'Content-Type', | 33 | 'Content-Type', |
119 | 'application/json' | 34 | 'application/json' |
120 | ) | 35 | ) |
@@ -123,10 +38,7 @@ class WallabagRestControllerTest extends WebTestCase | |||
123 | 38 | ||
124 | public function testGetOneEntryWrongUser() | 39 | public function testGetOneEntryWrongUser() |
125 | { | 40 | { |
126 | $client = $this->createClient(); | 41 | $entry = $this->client->getContainer() |
127 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
128 | |||
129 | $entry = $client->getContainer() | ||
130 | ->get('doctrine.orm.entity_manager') | 42 | ->get('doctrine.orm.entity_manager') |
131 | ->getRepository('WallabagCoreBundle:Entry') | 43 | ->getRepository('WallabagCoreBundle:Entry') |
132 | ->findOneBy(array('user' => 2, 'isArchived' => false)); | 44 | ->findOneBy(array('user' => 2, 'isArchived' => false)); |
@@ -135,21 +47,18 @@ class WallabagRestControllerTest extends WebTestCase | |||
135 | $this->markTestSkipped('No content found in db.'); | 47 | $this->markTestSkipped('No content found in db.'); |
136 | } | 48 | } |
137 | 49 | ||
138 | $client->request('GET', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers); | 50 | $this->client->request('GET', '/api/entries/'.$entry->getId().'.json'); |
139 | 51 | ||
140 | $this->assertEquals(403, $client->getResponse()->getStatusCode()); | 52 | $this->assertEquals(403, $this->client->getResponse()->getStatusCode()); |
141 | } | 53 | } |
142 | 54 | ||
143 | public function testGetEntries() | 55 | public function testGetEntries() |
144 | { | 56 | { |
145 | $client = $this->createClient(); | 57 | $this->client->request('GET', '/api/entries'); |
146 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
147 | |||
148 | $client->request('GET', '/api/entries', array(), array(), $headers); | ||
149 | 58 | ||
150 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 59 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
151 | 60 | ||
152 | $content = json_decode($client->getResponse()->getContent(), true); | 61 | $content = json_decode($this->client->getResponse()->getContent(), true); |
153 | 62 | ||
154 | $this->assertGreaterThanOrEqual(1, count($content)); | 63 | $this->assertGreaterThanOrEqual(1, count($content)); |
155 | $this->assertNotEmpty($content['_embedded']['items']); | 64 | $this->assertNotEmpty($content['_embedded']['items']); |
@@ -158,7 +67,7 @@ class WallabagRestControllerTest extends WebTestCase | |||
158 | $this->assertGreaterThanOrEqual(1, $content['pages']); | 67 | $this->assertGreaterThanOrEqual(1, $content['pages']); |
159 | 68 | ||
160 | $this->assertTrue( | 69 | $this->assertTrue( |
161 | $client->getResponse()->headers->contains( | 70 | $this->client->getResponse()->headers->contains( |
162 | 'Content-Type', | 71 | 'Content-Type', |
163 | 'application/json' | 72 | 'application/json' |
164 | ) | 73 | ) |
@@ -167,14 +76,11 @@ class WallabagRestControllerTest extends WebTestCase | |||
167 | 76 | ||
168 | public function testGetStarredEntries() | 77 | public function testGetStarredEntries() |
169 | { | 78 | { |
170 | $client = $this->createClient(); | 79 | $this->client->request('GET', '/api/entries', array('star' => 1, 'sort' => 'updated')); |
171 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
172 | 80 | ||
173 | $client->request('GET', '/api/entries', array('star' => 1, 'sort' => 'updated'), array(), $headers); | 81 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
174 | 82 | ||
175 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 83 | $content = json_decode($this->client->getResponse()->getContent(), true); |
176 | |||
177 | $content = json_decode($client->getResponse()->getContent(), true); | ||
178 | 84 | ||
179 | $this->assertGreaterThanOrEqual(1, count($content)); | 85 | $this->assertGreaterThanOrEqual(1, count($content)); |
180 | $this->assertNotEmpty($content['_embedded']['items']); | 86 | $this->assertNotEmpty($content['_embedded']['items']); |
@@ -183,7 +89,7 @@ class WallabagRestControllerTest extends WebTestCase | |||
183 | $this->assertGreaterThanOrEqual(1, $content['pages']); | 89 | $this->assertGreaterThanOrEqual(1, $content['pages']); |
184 | 90 | ||
185 | $this->assertTrue( | 91 | $this->assertTrue( |
186 | $client->getResponse()->headers->contains( | 92 | $this->client->getResponse()->headers->contains( |
187 | 'Content-Type', | 93 | 'Content-Type', |
188 | 'application/json' | 94 | 'application/json' |
189 | ) | 95 | ) |
@@ -192,14 +98,11 @@ class WallabagRestControllerTest extends WebTestCase | |||
192 | 98 | ||
193 | public function testGetArchiveEntries() | 99 | public function testGetArchiveEntries() |
194 | { | 100 | { |
195 | $client = $this->createClient(); | 101 | $this->client->request('GET', '/api/entries', array('archive' => 1)); |
196 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
197 | |||
198 | $client->request('GET', '/api/entries', array('archive' => 1), array(), $headers); | ||
199 | 102 | ||
200 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 103 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
201 | 104 | ||
202 | $content = json_decode($client->getResponse()->getContent(), true); | 105 | $content = json_decode($this->client->getResponse()->getContent(), true); |
203 | 106 | ||
204 | $this->assertGreaterThanOrEqual(1, count($content)); | 107 | $this->assertGreaterThanOrEqual(1, count($content)); |
205 | $this->assertNotEmpty($content['_embedded']['items']); | 108 | $this->assertNotEmpty($content['_embedded']['items']); |
@@ -208,7 +111,7 @@ class WallabagRestControllerTest extends WebTestCase | |||
208 | $this->assertGreaterThanOrEqual(1, $content['pages']); | 111 | $this->assertGreaterThanOrEqual(1, $content['pages']); |
209 | 112 | ||
210 | $this->assertTrue( | 113 | $this->assertTrue( |
211 | $client->getResponse()->headers->contains( | 114 | $this->client->getResponse()->headers->contains( |
212 | 'Content-Type', | 115 | 'Content-Type', |
213 | 'application/json' | 116 | 'application/json' |
214 | ) | 117 | ) |
@@ -217,10 +120,7 @@ class WallabagRestControllerTest extends WebTestCase | |||
217 | 120 | ||
218 | public function testDeleteEntry() | 121 | public function testDeleteEntry() |
219 | { | 122 | { |
220 | $client = $this->createClient(); | 123 | $entry = $this->client->getContainer() |
221 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
222 | |||
223 | $entry = $client->getContainer() | ||
224 | ->get('doctrine.orm.entity_manager') | 124 | ->get('doctrine.orm.entity_manager') |
225 | ->getRepository('WallabagCoreBundle:Entry') | 125 | ->getRepository('WallabagCoreBundle:Entry') |
226 | ->findOneByUser(1); | 126 | ->findOneByUser(1); |
@@ -229,36 +129,31 @@ class WallabagRestControllerTest extends WebTestCase | |||
229 | $this->markTestSkipped('No content found in db.'); | 129 | $this->markTestSkipped('No content found in db.'); |
230 | } | 130 | } |
231 | 131 | ||
232 | $client->request('DELETE', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers); | 132 | $this->client->request('DELETE', '/api/entries/'.$entry->getId().'.json'); |
233 | 133 | ||
234 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 134 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
235 | 135 | ||
236 | $content = json_decode($client->getResponse()->getContent(), true); | 136 | $content = json_decode($this->client->getResponse()->getContent(), true); |
237 | 137 | ||
238 | $this->assertEquals($entry->getTitle(), $content['title']); | 138 | $this->assertEquals($entry->getTitle(), $content['title']); |
239 | $this->assertEquals($entry->getUrl(), $content['url']); | 139 | $this->assertEquals($entry->getUrl(), $content['url']); |
240 | 140 | ||
241 | // We'll try to delete this entry again | 141 | // We'll try to delete this entry again |
242 | $headers = $this->generateHeaders('admin', 'mypassword'); | 142 | $this->client->request('DELETE', '/api/entries/'.$entry->getId().'.json'); |
243 | |||
244 | $client->request('DELETE', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers); | ||
245 | 143 | ||
246 | $this->assertEquals(404, $client->getResponse()->getStatusCode()); | 144 | $this->assertEquals(404, $this->client->getResponse()->getStatusCode()); |
247 | } | 145 | } |
248 | 146 | ||
249 | public function testPostEntry() | 147 | public function testPostEntry() |
250 | { | 148 | { |
251 | $client = $this->createClient(); | 149 | $this->client->request('POST', '/api/entries.json', array( |
252 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
253 | |||
254 | $client->request('POST', '/api/entries.json', array( | ||
255 | 'url' => 'http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', | 150 | 'url' => 'http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', |
256 | 'tags' => 'google', | 151 | 'tags' => 'google', |
257 | ), array(), $headers); | 152 | )); |
258 | 153 | ||
259 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 154 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
260 | 155 | ||
261 | $content = json_decode($client->getResponse()->getContent(), true); | 156 | $content = json_decode($this->client->getResponse()->getContent(), true); |
262 | 157 | ||
263 | $this->assertGreaterThan(0, $content['id']); | 158 | $this->assertGreaterThan(0, $content['id']); |
264 | $this->assertEquals('http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', $content['url']); | 159 | $this->assertEquals('http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', $content['url']); |
@@ -269,10 +164,7 @@ class WallabagRestControllerTest extends WebTestCase | |||
269 | 164 | ||
270 | public function testPatchEntry() | 165 | public function testPatchEntry() |
271 | { | 166 | { |
272 | $client = $this->createClient(); | 167 | $entry = $this->client->getContainer() |
273 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
274 | |||
275 | $entry = $client->getContainer() | ||
276 | ->get('doctrine.orm.entity_manager') | 168 | ->get('doctrine.orm.entity_manager') |
277 | ->getRepository('WallabagCoreBundle:Entry') | 169 | ->getRepository('WallabagCoreBundle:Entry') |
278 | ->findOneByUser(1); | 170 | ->findOneByUser(1); |
@@ -284,16 +176,16 @@ class WallabagRestControllerTest extends WebTestCase | |||
284 | // hydrate the tags relations | 176 | // hydrate the tags relations |
285 | $nbTags = count($entry->getTags()); | 177 | $nbTags = count($entry->getTags()); |
286 | 178 | ||
287 | $client->request('PATCH', '/api/entries/'.$entry->getId().'.json', array( | 179 | $this->client->request('PATCH', '/api/entries/'.$entry->getId().'.json', array( |
288 | 'title' => 'New awesome title', | 180 | 'title' => 'New awesome title', |
289 | 'tags' => 'new tag '.uniqid(), | 181 | 'tags' => 'new tag '.uniqid(), |
290 | 'star' => true, | 182 | 'star' => true, |
291 | 'archive' => false, | 183 | 'archive' => false, |
292 | ), array(), $headers); | 184 | )); |
293 | 185 | ||
294 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 186 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
295 | 187 | ||
296 | $content = json_decode($client->getResponse()->getContent(), true); | 188 | $content = json_decode($this->client->getResponse()->getContent(), true); |
297 | 189 | ||
298 | $this->assertEquals($entry->getId(), $content['id']); | 190 | $this->assertEquals($entry->getId(), $content['id']); |
299 | $this->assertEquals($entry->getUrl(), $content['url']); | 191 | $this->assertEquals($entry->getUrl(), $content['url']); |
@@ -303,10 +195,7 @@ class WallabagRestControllerTest extends WebTestCase | |||
303 | 195 | ||
304 | public function testGetTagsEntry() | 196 | public function testGetTagsEntry() |
305 | { | 197 | { |
306 | $client = $this->createClient(); | 198 | $entry = $this->client->getContainer() |
307 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
308 | |||
309 | $entry = $client->getContainer() | ||
310 | ->get('doctrine.orm.entity_manager') | 199 | ->get('doctrine.orm.entity_manager') |
311 | ->getRepository('WallabagCoreBundle:Entry') | 200 | ->getRepository('WallabagCoreBundle:Entry') |
312 | ->findOneWithTags(1); | 201 | ->findOneWithTags(1); |
@@ -322,17 +211,14 @@ class WallabagRestControllerTest extends WebTestCase | |||
322 | $tags[] = array('id' => $tag->getId(), 'label' => $tag->getLabel()); | 211 | $tags[] = array('id' => $tag->getId(), 'label' => $tag->getLabel()); |
323 | } | 212 | } |
324 | 213 | ||
325 | $client->request('GET', '/api/entries/'.$entry->getId().'/tags', array(), array(), $headers); | 214 | $this->client->request('GET', '/api/entries/'.$entry->getId().'/tags'); |
326 | 215 | ||
327 | $this->assertEquals(json_encode($tags, JSON_HEX_QUOT), $client->getResponse()->getContent()); | 216 | $this->assertEquals(json_encode($tags, JSON_HEX_QUOT), $this->client->getResponse()->getContent()); |
328 | } | 217 | } |
329 | 218 | ||
330 | public function testPostTagsOnEntry() | 219 | public function testPostTagsOnEntry() |
331 | { | 220 | { |
332 | $client = $this->createClient(); | 221 | $entry = $this->client->getContainer() |
333 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
334 | |||
335 | $entry = $client->getContainer() | ||
336 | ->get('doctrine.orm.entity_manager') | 222 | ->get('doctrine.orm.entity_manager') |
337 | ->getRepository('WallabagCoreBundle:Entry') | 223 | ->getRepository('WallabagCoreBundle:Entry') |
338 | ->findOneByUser(1); | 224 | ->findOneByUser(1); |
@@ -345,16 +231,16 @@ class WallabagRestControllerTest extends WebTestCase | |||
345 | 231 | ||
346 | $newTags = 'tag1,tag2,tag3'; | 232 | $newTags = 'tag1,tag2,tag3'; |
347 | 233 | ||
348 | $client->request('POST', '/api/entries/'.$entry->getId().'/tags', array('tags' => $newTags), array(), $headers); | 234 | $this->client->request('POST', '/api/entries/'.$entry->getId().'/tags', array('tags' => $newTags)); |
349 | 235 | ||
350 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 236 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
351 | 237 | ||
352 | $content = json_decode($client->getResponse()->getContent(), true); | 238 | $content = json_decode($this->client->getResponse()->getContent(), true); |
353 | 239 | ||
354 | $this->assertArrayHasKey('tags', $content); | 240 | $this->assertArrayHasKey('tags', $content); |
355 | $this->assertEquals($nbTags + 3, count($content['tags'])); | 241 | $this->assertEquals($nbTags + 3, count($content['tags'])); |
356 | 242 | ||
357 | $entryDB = $client->getContainer() | 243 | $entryDB = $this->client->getContainer() |
358 | ->get('doctrine.orm.entity_manager') | 244 | ->get('doctrine.orm.entity_manager') |
359 | ->getRepository('WallabagCoreBundle:Entry') | 245 | ->getRepository('WallabagCoreBundle:Entry') |
360 | ->find($entry->getId()); | 246 | ->find($entry->getId()); |
@@ -369,15 +255,13 @@ class WallabagRestControllerTest extends WebTestCase | |||
369 | } | 255 | } |
370 | } | 256 | } |
371 | 257 | ||
372 | public function testDeleteOneTagEntrie() | 258 | public function testDeleteOneTagEntry() |
373 | { | 259 | { |
374 | $client = $this->createClient(); | 260 | $entry = $this->client->getContainer() |
375 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
376 | |||
377 | $entry = $client->getContainer() | ||
378 | ->get('doctrine.orm.entity_manager') | 261 | ->get('doctrine.orm.entity_manager') |
379 | ->getRepository('WallabagCoreBundle:Entry') | 262 | ->getRepository('WallabagCoreBundle:Entry') |
380 | ->findOneByUser(1); | 263 | ->findOneWithTags(1); |
264 | $entry = $entry[0]; | ||
381 | 265 | ||
382 | if (!$entry) { | 266 | if (!$entry) { |
383 | $this->markTestSkipped('No content found in db.'); | 267 | $this->markTestSkipped('No content found in db.'); |
@@ -387,11 +271,11 @@ class WallabagRestControllerTest extends WebTestCase | |||
387 | $nbTags = count($entry->getTags()); | 271 | $nbTags = count($entry->getTags()); |
388 | $tag = $entry->getTags()[0]; | 272 | $tag = $entry->getTags()[0]; |
389 | 273 | ||
390 | $client->request('DELETE', '/api/entries/'.$entry->getId().'/tags/'.$tag->getId().'.json', array(), array(), $headers); | 274 | $this->client->request('DELETE', '/api/entries/'.$entry->getId().'/tags/'.$tag->getId().'.json'); |
391 | 275 | ||
392 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 276 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
393 | 277 | ||
394 | $content = json_decode($client->getResponse()->getContent(), true); | 278 | $content = json_decode($this->client->getResponse()->getContent(), true); |
395 | 279 | ||
396 | $this->assertArrayHasKey('tags', $content); | 280 | $this->assertArrayHasKey('tags', $content); |
397 | $this->assertEquals($nbTags - 1, count($content['tags'])); | 281 | $this->assertEquals($nbTags - 1, count($content['tags'])); |
@@ -399,14 +283,11 @@ class WallabagRestControllerTest extends WebTestCase | |||
399 | 283 | ||
400 | public function testGetUserTags() | 284 | public function testGetUserTags() |
401 | { | 285 | { |
402 | $client = $this->createClient(); | 286 | $this->client->request('GET', '/api/tags.json'); |
403 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
404 | |||
405 | $client->request('GET', '/api/tags.json', array(), array(), $headers); | ||
406 | 287 | ||
407 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 288 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
408 | 289 | ||
409 | $content = json_decode($client->getResponse()->getContent(), true); | 290 | $content = json_decode($this->client->getResponse()->getContent(), true); |
410 | 291 | ||
411 | $this->assertGreaterThan(0, $content); | 292 | $this->assertGreaterThan(0, $content); |
412 | $this->assertArrayHasKey('id', $content[0]); | 293 | $this->assertArrayHasKey('id', $content[0]); |
@@ -420,14 +301,11 @@ class WallabagRestControllerTest extends WebTestCase | |||
420 | */ | 301 | */ |
421 | public function testDeleteUserTag($tag) | 302 | public function testDeleteUserTag($tag) |
422 | { | 303 | { |
423 | $client = $this->createClient(); | 304 | $this->client->request('DELETE', '/api/tags/'.$tag['id'].'.json'); |
424 | $headers = $this->generateHeaders('admin', 'mypassword'); | ||
425 | |||
426 | $client->request('DELETE', '/api/tags/'.$tag['id'].'.json', array(), array(), $headers); | ||
427 | 305 | ||
428 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); | 306 | $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); |
429 | 307 | ||
430 | $content = json_decode($client->getResponse()->getContent(), true); | 308 | $content = json_decode($this->client->getResponse()->getContent(), true); |
431 | 309 | ||
432 | $this->assertArrayHasKey('label', $content); | 310 | $this->assertArrayHasKey('label', $content); |
433 | $this->assertEquals($tag['label'], $content['label']); | 311 | $this->assertEquals($tag['label'], $content['label']); |
diff --git a/src/Wallabag/ApiBundle/WallabagApiBundle.php b/src/Wallabag/ApiBundle/WallabagApiBundle.php index 2484f277..19d887ab 100644 --- a/src/Wallabag/ApiBundle/WallabagApiBundle.php +++ b/src/Wallabag/ApiBundle/WallabagApiBundle.php | |||
@@ -3,16 +3,7 @@ | |||
3 | namespace Wallabag\ApiBundle; | 3 | namespace Wallabag\ApiBundle; |
4 | 4 | ||
5 | use Symfony\Component\HttpKernel\Bundle\Bundle; | 5 | use Symfony\Component\HttpKernel\Bundle\Bundle; |
6 | use Wallabag\ApiBundle\DependencyInjection\Security\Factory\WsseFactory; | ||
7 | use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
8 | 6 | ||
9 | class WallabagApiBundle extends Bundle | 7 | class WallabagApiBundle extends Bundle |
10 | { | 8 | { |
11 | public function build(ContainerBuilder $container) | ||
12 | { | ||
13 | parent::build($container); | ||
14 | |||
15 | $extension = $container->getExtension('security'); | ||
16 | $extension->addSecurityListenerFactory(new WsseFactory()); | ||
17 | } | ||
18 | } | 9 | } |
diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php index 5affdee8..27c323b7 100644 --- a/src/Wallabag/CoreBundle/Controller/ConfigController.php +++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php | |||
@@ -25,6 +25,7 @@ class ConfigController extends Controller | |||
25 | { | 25 | { |
26 | $em = $this->getDoctrine()->getManager(); | 26 | $em = $this->getDoctrine()->getManager(); |
27 | $config = $this->getConfig(); | 27 | $config = $this->getConfig(); |
28 | $userManager = $this->container->get('fos_user.user_manager'); | ||
28 | $user = $this->getUser(); | 29 | $user = $this->getUser(); |
29 | 30 | ||
30 | // handle basic config detail (this form is defined as a service) | 31 | // handle basic config detail (this form is defined as a service) |
@@ -52,9 +53,8 @@ class ConfigController extends Controller | |||
52 | $pwdForm->handleRequest($request); | 53 | $pwdForm->handleRequest($request); |
53 | 54 | ||
54 | if ($pwdForm->isValid()) { | 55 | if ($pwdForm->isValid()) { |
55 | $user->setPassword($pwdForm->get('new_password')->getData()); | 56 | $user->setPlainPassword($pwdForm->get('new_password')->getData()); |
56 | $em->persist($user); | 57 | $userManager->updateUser($user, true); |
57 | $em->flush(); | ||
58 | 58 | ||
59 | $this->get('session')->getFlashBag()->add( | 59 | $this->get('session')->getFlashBag()->add( |
60 | 'notice', | 60 | 'notice', |
@@ -69,8 +69,7 @@ class ConfigController extends Controller | |||
69 | $userForm->handleRequest($request); | 69 | $userForm->handleRequest($request); |
70 | 70 | ||
71 | if ($userForm->isValid()) { | 71 | if ($userForm->isValid()) { |
72 | $em->persist($user); | 72 | $userManager->updateUser($user, true); |
73 | $em->flush(); | ||
74 | 73 | ||
75 | $this->get('session')->getFlashBag()->add( | 74 | $this->get('session')->getFlashBag()->add( |
76 | 'notice', | 75 | 'notice', |
@@ -97,14 +96,14 @@ class ConfigController extends Controller | |||
97 | } | 96 | } |
98 | 97 | ||
99 | // handle adding new user | 98 | // handle adding new user |
100 | $newUser = new User(); | 99 | $newUser = $userManager->createUser(); |
101 | // enable created user by default | 100 | // enable created user by default |
102 | $newUser->setEnabled(true); | 101 | $newUser->setEnabled(true); |
103 | $newUserForm = $this->createForm(new NewUserType(), $newUser, array('validation_groups' => array('Profile'))); | 102 | $newUserForm = $this->createForm(new NewUserType(), $newUser, array('validation_groups' => array('Profile'))); |
104 | $newUserForm->handleRequest($request); | 103 | $newUserForm->handleRequest($request); |
105 | 104 | ||
106 | if ($newUserForm->isValid()) { | 105 | if ($newUserForm->isValid() && $this->get('security.authorization_checker')->isGranted('ROLE_SUPER_ADMIN')) { |
107 | $em->persist($newUser); | 106 | $userManager->updateUser($newUser, true); |
108 | 107 | ||
109 | $config = new Config($newUser); | 108 | $config = new Config($newUser); |
110 | $config->setTheme($this->container->getParameter('theme')); | 109 | $config->setTheme($this->container->getParameter('theme')); |
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php index 4ef53329..811451da 100644 --- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php +++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php | |||
@@ -18,8 +18,9 @@ class LoadUserData extends AbstractFixture implements OrderedFixtureInterface | |||
18 | $userAdmin->setName('Big boss'); | 18 | $userAdmin->setName('Big boss'); |
19 | $userAdmin->setEmail('bigboss@wallabag.org'); | 19 | $userAdmin->setEmail('bigboss@wallabag.org'); |
20 | $userAdmin->setUsername('admin'); | 20 | $userAdmin->setUsername('admin'); |
21 | $userAdmin->setPassword('mypassword'); | 21 | $userAdmin->setPlainPassword('mypassword'); |
22 | $userAdmin->setEnabled(true); | 22 | $userAdmin->setEnabled(true); |
23 | $userAdmin->addRole('ROLE_SUPER_ADMIN'); | ||
23 | 24 | ||
24 | $manager->persist($userAdmin); | 25 | $manager->persist($userAdmin); |
25 | 26 | ||
@@ -29,7 +30,7 @@ class LoadUserData extends AbstractFixture implements OrderedFixtureInterface | |||
29 | $bobUser->setName('Bobby'); | 30 | $bobUser->setName('Bobby'); |
30 | $bobUser->setEmail('bobby@wallabag.org'); | 31 | $bobUser->setEmail('bobby@wallabag.org'); |
31 | $bobUser->setUsername('bob'); | 32 | $bobUser->setUsername('bob'); |
32 | $bobUser->setPassword('mypassword'); | 33 | $bobUser->setPlainPassword('mypassword'); |
33 | $bobUser->setEnabled(true); | 34 | $bobUser->setEnabled(true); |
34 | 35 | ||
35 | $manager->persist($bobUser); | 36 | $manager->persist($bobUser); |
diff --git a/src/Wallabag/CoreBundle/Entity/User.php b/src/Wallabag/CoreBundle/Entity/User.php index a6002352..ae2902a3 100644 --- a/src/Wallabag/CoreBundle/Entity/User.php +++ b/src/Wallabag/CoreBundle/Entity/User.php | |||
@@ -6,7 +6,6 @@ use Doctrine\Common\Collections\ArrayCollection; | |||
6 | use Doctrine\ORM\Mapping as ORM; | 6 | use Doctrine\ORM\Mapping as ORM; |
7 | use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; | 7 | use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; |
8 | use Symfony\Component\Security\Core\User\UserInterface; | 8 | use Symfony\Component\Security\Core\User\UserInterface; |
9 | use Symfony\Component\Security\Core\User\AdvancedUserInterface; | ||
10 | use JMS\Serializer\Annotation\ExclusionPolicy; | 9 | use JMS\Serializer\Annotation\ExclusionPolicy; |
11 | use JMS\Serializer\Annotation\Expose; | 10 | use JMS\Serializer\Annotation\Expose; |
12 | use FOS\UserBundle\Model\User as BaseUser; | 11 | use FOS\UserBundle\Model\User as BaseUser; |
@@ -22,7 +21,7 @@ use FOS\UserBundle\Model\User as BaseUser; | |||
22 | * @UniqueEntity("email") | 21 | * @UniqueEntity("email") |
23 | * @UniqueEntity("username") | 22 | * @UniqueEntity("username") |
24 | */ | 23 | */ |
25 | class User extends BaseUser implements AdvancedUserInterface, \Serializable | 24 | class User extends BaseUser |
26 | { | 25 | { |
27 | /** | 26 | /** |
28 | * @var int | 27 | * @var int |
@@ -75,6 +74,7 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable | |||
75 | parent::__construct(); | 74 | parent::__construct(); |
76 | $this->entries = new ArrayCollection(); | 75 | $this->entries = new ArrayCollection(); |
77 | $this->tags = new ArrayCollection(); | 76 | $this->tags = new ArrayCollection(); |
77 | $this->roles = array('ROLE_USER'); | ||
78 | } | 78 | } |
79 | 79 | ||
80 | /** | 80 | /** |
@@ -91,24 +91,6 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable | |||
91 | } | 91 | } |
92 | 92 | ||
93 | /** | 93 | /** |
94 | * Set password. | ||
95 | * | ||
96 | * @param string $password | ||
97 | * | ||
98 | * @return User | ||
99 | */ | ||
100 | public function setPassword($password) | ||
101 | { | ||
102 | if (!$password && 0 === strlen($password)) { | ||
103 | return; | ||
104 | } | ||
105 | |||
106 | $this->password = sha1($password.$this->getUsername().$this->getSalt()); | ||
107 | |||
108 | return $this; | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * Set name. | 94 | * Set name. |
113 | * | 95 | * |
114 | * @param string $name | 96 | * @param string $name |
diff --git a/src/Wallabag/CoreBundle/EventListener/AuthenticationListener.php b/src/Wallabag/CoreBundle/EventListener/AuthenticationListener.php new file mode 100644 index 00000000..7c2826ec --- /dev/null +++ b/src/Wallabag/CoreBundle/EventListener/AuthenticationListener.php | |||
@@ -0,0 +1,44 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\EventListener; | ||
4 | |||
5 | use FOS\UserBundle\FOSUserEvents; | ||
6 | use Symfony\Component\DependencyInjection\Container; | ||
7 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||
8 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
9 | use FOS\UserBundle\Event\FilterUserResponseEvent; | ||
10 | use Wallabag\CoreBundle\Entity\Config; | ||
11 | |||
12 | class AuthenticationListener implements EventSubscriberInterface | ||
13 | { | ||
14 | private $em; | ||
15 | private $container; | ||
16 | |||
17 | public function __construct(Container $container, $em) | ||
18 | { | ||
19 | $this->container = $container; | ||
20 | $this->em = $em; | ||
21 | } | ||
22 | |||
23 | public static function getSubscribedEvents() | ||
24 | { | ||
25 | return array( | ||
26 | FOSUserEvents::REGISTRATION_CONFIRMED => 'authenticate', | ||
27 | ); | ||
28 | } | ||
29 | |||
30 | public function authenticate(FilterUserResponseEvent $event, $eventName = null, EventDispatcherInterface $eventDispatcher = null) | ||
31 | { | ||
32 | if (!$event->getUser()->isEnabled()) { | ||
33 | return; | ||
34 | } | ||
35 | |||
36 | $config = new Config($event->getUser()); | ||
37 | $config->setTheme($this->container->getParameter('theme')); | ||
38 | $config->setItemsPerPage($this->container->getParameter('items_on_page')); | ||
39 | $config->setRssLimit($this->container->getParameter('rss_limit')); | ||
40 | $config->setLanguage($this->container->getParameter('language')); | ||
41 | $this->em->persist($config); | ||
42 | $this->em->flush(); | ||
43 | } | ||
44 | } | ||
diff --git a/src/Wallabag/CoreBundle/Form/Type/NewUserType.php b/src/Wallabag/CoreBundle/Form/Type/NewUserType.php index 985cb55b..ea7bb7ae 100644 --- a/src/Wallabag/CoreBundle/Form/Type/NewUserType.php +++ b/src/Wallabag/CoreBundle/Form/Type/NewUserType.php | |||
@@ -13,7 +13,8 @@ class NewUserType extends AbstractType | |||
13 | { | 13 | { |
14 | $builder | 14 | $builder |
15 | ->add('username', 'text', array('required' => true)) | 15 | ->add('username', 'text', array('required' => true)) |
16 | ->add('password', 'password', array( | 16 | ->add('plainPassword', 'repeated', array( |
17 | 'type' => 'password', | ||
17 | 'constraints' => array( | 18 | 'constraints' => array( |
18 | new Constraints\Length(array( | 19 | new Constraints\Length(array( |
19 | 'min' => 8, | 20 | 'min' => 8, |
diff --git a/src/Wallabag/CoreBundle/Form/Type/RegistrationType.php b/src/Wallabag/CoreBundle/Form/Type/RegistrationType.php new file mode 100644 index 00000000..47d4f341 --- /dev/null +++ b/src/Wallabag/CoreBundle/Form/Type/RegistrationType.php | |||
@@ -0,0 +1,24 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Form\Type; | ||
4 | |||
5 | use Symfony\Component\Form\AbstractType; | ||
6 | use Symfony\Component\Form\FormBuilderInterface; | ||
7 | |||
8 | class RegistrationType extends AbstractType | ||
9 | { | ||
10 | public function buildForm(FormBuilderInterface $builder, array $options) | ||
11 | { | ||
12 | $builder->add('name'); | ||
13 | } | ||
14 | |||
15 | public function getParent() | ||
16 | { | ||
17 | return 'fos_user_registration'; | ||
18 | } | ||
19 | |||
20 | public function getName() | ||
21 | { | ||
22 | return 'wallabag_user_registration'; | ||
23 | } | ||
24 | } | ||
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml index 3beb5d0e..96ea482a 100644 --- a/src/Wallabag/CoreBundle/Resources/config/services.yml +++ b/src/Wallabag/CoreBundle/Resources/config/services.yml | |||
@@ -13,6 +13,11 @@ services: | |||
13 | tags: | 13 | tags: |
14 | - { name: form.type, alias: config } | 14 | - { name: form.type, alias: config } |
15 | 15 | ||
16 | wallabag_core.form.registration: | ||
17 | class: Wallabag\CoreBundle\Form\Type\RegistrationType | ||
18 | tags: | ||
19 | - { name: form.type, alias: wallabag_user_registration } | ||
20 | |||
16 | wallabag_core.form.type.forgot_password: | 21 | wallabag_core.form.type.forgot_password: |
17 | class: Wallabag\CoreBundle\Form\Type\ForgotPasswordType | 22 | class: Wallabag\CoreBundle\Form\Type\ForgotPasswordType |
18 | arguments: | 23 | arguments: |
@@ -40,3 +45,9 @@ services: | |||
40 | class: Wallabag\CoreBundle\Helper\ContentProxy | 45 | class: Wallabag\CoreBundle\Helper\ContentProxy |
41 | arguments: | 46 | arguments: |
42 | - @wallabag_core.graby | 47 | - @wallabag_core.graby |
48 | |||
49 | wallabag_core.registration_confirmed: | ||
50 | class: Wallabag\CoreBundle\EventListener\AuthenticationListener | ||
51 | arguments: [@service_container, @doctrine.orm.entity_manager] | ||
52 | tags: | ||
53 | - { name: kernel.event_subscriber } | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig index c90bb2e3..64305b16 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig | |||
@@ -135,6 +135,7 @@ | |||
135 | {{ form_rest(form.pwd) }} | 135 | {{ form_rest(form.pwd) }} |
136 | </form> | 136 | </form> |
137 | 137 | ||
138 | {% if is_granted('ROLE_SUPER_ADMIN') %} | ||
138 | <h2>{% trans %}Add a user{% endtrans %}</h2> | 139 | <h2>{% trans %}Add a user{% endtrans %}</h2> |
139 | 140 | ||
140 | <form action="{{ path('config') }}" method="post" {{ form_enctype(form.new_user) }}> | 141 | <form action="{{ path('config') }}" method="post" {{ form_enctype(form.new_user) }}> |
@@ -150,9 +151,17 @@ | |||
150 | 151 | ||
151 | <fieldset class="w500p inline"> | 152 | <fieldset class="w500p inline"> |
152 | <div class="row"> | 153 | <div class="row"> |
153 | {{ form_label(form.new_user.password) }} | 154 | {{ form_label(form.new_user.plainPassword.first) }} |
154 | {{ form_errors(form.new_user.password) }} | 155 | {{ form_errors(form.new_user.plainPassword.first) }} |
155 | {{ form_widget(form.new_user.password) }} | 156 | {{ form_widget(form.new_user.plainPassword.first) }} |
157 | </div> | ||
158 | </fieldset> | ||
159 | |||
160 | <fieldset class="w500p inline"> | ||
161 | <div class="row"> | ||
162 | {{ form_label(form.new_user.plainPassword.second) }} | ||
163 | {{ form_errors(form.new_user.plainPassword.second) }} | ||
164 | {{ form_widget(form.new_user.plainPassword.second) }} | ||
156 | </div> | 165 | </div> |
157 | </fieldset> | 166 | </fieldset> |
158 | 167 | ||
@@ -165,5 +174,6 @@ | |||
165 | </fieldset> | 174 | </fieldset> |
166 | 175 | ||
167 | {{ form_rest(form.new_user) }} | 176 | {{ form_rest(form.new_user) }} |
177 | {% endif %} | ||
168 | </form> | 178 | </form> |
169 | {% endblock %} | 179 | {% endblock %} |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig index 0ff21f22..0d8e9f24 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig | |||
@@ -15,7 +15,9 @@ | |||
15 | <li class="tab col s3"><a href="#set2">{% trans %}RSS{% endtrans %}</a></li> | 15 | <li class="tab col s3"><a href="#set2">{% trans %}RSS{% endtrans %}</a></li> |
16 | <li class="tab col s3"><a href="#set3">{% trans %}User information{% endtrans %}</a></li> | 16 | <li class="tab col s3"><a href="#set3">{% trans %}User information{% endtrans %}</a></li> |
17 | <li class="tab col s3"><a href="#set4">{% trans %}Password{% endtrans %}</a></li> | 17 | <li class="tab col s3"><a href="#set4">{% trans %}Password{% endtrans %}</a></li> |
18 | {% if is_granted('ROLE_SUPER_ADMIN') %} | ||
18 | <li class="tab col s3"><a href="#set5">{% trans %}Add a user{% endtrans %}</a></li> | 19 | <li class="tab col s3"><a href="#set5">{% trans %}Add a user{% endtrans %}</a></li> |
20 | {% endif %} | ||
19 | </ul> | 21 | </ul> |
20 | </div> | 22 | </div> |
21 | 23 | ||
@@ -175,7 +177,7 @@ | |||
175 | </form> | 177 | </form> |
176 | </div> | 178 | </div> |
177 | 179 | ||
178 | 180 | {% if is_granted('ROLE_SUPER_ADMIN') %} | |
179 | <div id="set5" class="col s12"> | 181 | <div id="set5" class="col s12"> |
180 | <form action="{{ path('config') }}#set5" method="post" {{ form_enctype(form.new_user) }}> | 182 | <form action="{{ path('config') }}#set5" method="post" {{ form_enctype(form.new_user) }}> |
181 | {{ form_errors(form.new_user) }} | 183 | {{ form_errors(form.new_user) }} |
@@ -190,9 +192,17 @@ | |||
190 | 192 | ||
191 | <div class="row"> | 193 | <div class="row"> |
192 | <div class="input-field col s12"> | 194 | <div class="input-field col s12"> |
193 | {{ form_label(form.new_user.password) }} | 195 | {{ form_label(form.new_user.plainPassword.first) }} |
194 | {{ form_errors(form.new_user.password) }} | 196 | {{ form_errors(form.new_user.plainPassword.first) }} |
195 | {{ form_widget(form.new_user.password) }} | 197 | {{ form_widget(form.new_user.plainPassword.first) }} |
198 | </div> | ||
199 | </div> | ||
200 | |||
201 | <div class="row"> | ||
202 | <div class="input-field col s12"> | ||
203 | {{ form_label(form.new_user.plainPassword.second) }} | ||
204 | {{ form_errors(form.new_user.plainPassword.second) }} | ||
205 | {{ form_widget(form.new_user.plainPassword.second) }} | ||
196 | </div> | 206 | </div> |
197 | </div> | 207 | </div> |
198 | 208 | ||
@@ -211,6 +221,7 @@ | |||
211 | 221 | ||
212 | </form> | 222 | </form> |
213 | </div> | 223 | </div> |
224 | {% endif %} | ||
214 | </div> | 225 | </div> |
215 | 226 | ||
216 | </div> | 227 | </div> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Security/login.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Security/login.html.twig index 4eb6d2b8..10f380fe 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Security/login.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Security/login.html.twig | |||
@@ -49,6 +49,7 @@ | |||
49 | {% trans %}Login{% endtrans %} | 49 | {% trans %}Login{% endtrans %} |
50 | <i class="mdi-content-send right"></i> | 50 | <i class="mdi-content-send right"></i> |
51 | </button> | 51 | </button> |
52 | <a href="{{ path('fos_user_registration_register') }}">{% trans %}Register{% endtrans %}</a> | ||
52 | </div> | 53 | </div> |
53 | </form> | 54 | </form> |
54 | </div> | 55 | </div> |
diff --git a/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php b/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php index 3407fc5e..708a07b1 100644 --- a/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php +++ b/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php | |||
@@ -258,7 +258,8 @@ class ConfigControllerTest extends WallabagCoreTestCase | |||
258 | array( | 258 | array( |
259 | array( | 259 | array( |
260 | 'new_user[username]' => '', | 260 | 'new_user[username]' => '', |
261 | 'new_user[password]' => '', | 261 | 'new_user[plainPassword][first]' => '', |
262 | 'new_user[plainPassword][second]' => '', | ||
262 | 'new_user[email]' => '', | 263 | 'new_user[email]' => '', |
263 | ), | 264 | ), |
264 | 'Please enter a username', | 265 | 'Please enter a username', |
@@ -266,7 +267,8 @@ class ConfigControllerTest extends WallabagCoreTestCase | |||
266 | array( | 267 | array( |
267 | array( | 268 | array( |
268 | 'new_user[username]' => 'a', | 269 | 'new_user[username]' => 'a', |
269 | 'new_user[password]' => 'mypassword', | 270 | 'new_user[plainPassword][first]' => 'mypassword', |
271 | 'new_user[plainPassword][second]' => 'mypassword', | ||
270 | 'new_user[email]' => '', | 272 | 'new_user[email]' => '', |
271 | ), | 273 | ), |
272 | 'The username is too short', | 274 | 'The username is too short', |
@@ -274,7 +276,8 @@ class ConfigControllerTest extends WallabagCoreTestCase | |||
274 | array( | 276 | array( |
275 | array( | 277 | array( |
276 | 'new_user[username]' => 'wallace', | 278 | 'new_user[username]' => 'wallace', |
277 | 'new_user[password]' => 'mypassword', | 279 | 'new_user[plainPassword][first]' => 'mypassword', |
280 | 'new_user[plainPassword][second]' => 'mypassword', | ||
278 | 'new_user[email]' => 'test', | 281 | 'new_user[email]' => 'test', |
279 | ), | 282 | ), |
280 | 'The email is not valid', | 283 | 'The email is not valid', |
@@ -282,11 +285,21 @@ class ConfigControllerTest extends WallabagCoreTestCase | |||
282 | array( | 285 | array( |
283 | array( | 286 | array( |
284 | 'new_user[username]' => 'admin', | 287 | 'new_user[username]' => 'admin', |
285 | 'new_user[password]' => 'wallacewallace', | 288 | 'new_user[plainPassword][first]' => 'wallacewallace', |
289 | 'new_user[plainPassword][second]' => 'wallacewallace', | ||
286 | 'new_user[email]' => 'wallace@wallace.me', | 290 | 'new_user[email]' => 'wallace@wallace.me', |
287 | ), | 291 | ), |
288 | 'The username is already used', | 292 | 'The username is already used', |
289 | ), | 293 | ), |
294 | array( | ||
295 | array( | ||
296 | 'new_user[username]' => 'wallace', | ||
297 | 'new_user[plainPassword][first]' => 'mypassword1', | ||
298 | 'new_user[plainPassword][second]' => 'mypassword2', | ||
299 | 'new_user[email]' => 'wallace@wallace.me', | ||
300 | ), | ||
301 | 'This value is not valid', | ||
302 | ), | ||
290 | ); | 303 | ); |
291 | } | 304 | } |
292 | 305 | ||
@@ -325,7 +338,8 @@ class ConfigControllerTest extends WallabagCoreTestCase | |||
325 | 338 | ||
326 | $data = array( | 339 | $data = array( |
327 | 'new_user[username]' => 'wallace', | 340 | 'new_user[username]' => 'wallace', |
328 | 'new_user[password]' => 'wallace1', | 341 | 'new_user[plainPassword][first]' => 'wallace1', |
342 | 'new_user[plainPassword][second]' => 'wallace1', | ||
329 | 'new_user[email]' => 'wallace@wallace.me', | 343 | 'new_user[email]' => 'wallace@wallace.me', |
330 | ); | 344 | ); |
331 | 345 | ||