linkedin_sign_in 0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.travis.yml +18 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +155 -0
- data/MIT-LICENSE +20 -0
- data/README.md +154 -0
- data/Rakefile +40 -0
- data/SECURITY.md +3 -0
- data/app/controllers/linkedin_sign_in/authorizations_controller.rb +17 -0
- data/app/controllers/linkedin_sign_in/base_controller.rb +15 -0
- data/app/controllers/linkedin_sign_in/callbacks_controller.rb +27 -0
- data/app/helpers/linkedin_sign_in/button_helper.rb +7 -0
- data/bin/rails +16 -0
- data/config/routes.rb +4 -0
- data/lib/linkedin-id-token.rb +190 -0
- data/lib/linkedin_sign_in/engine.rb +32 -0
- data/lib/linkedin_sign_in/identity.rb +55 -0
- data/lib/linkedin_sign_in/redirect_protector.rb +25 -0
- data/lib/linkedin_sign_in.rb +10 -0
- data/linkedin_sign_in.gemspec +21 -0
- data/test/certificate.pem +19 -0
- data/test/controllers/authorizations_controller_test.rb +26 -0
- data/test/controllers/callbacks_controller_test.rb +36 -0
- data/test/dummy/.ruby-version +1 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/config/manifest.js +3 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/javascripts/cable.js +13 -0
- data/test/dummy/app/assets/javascripts/channels/.keep +0 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/channels/application_cable/channel.rb +4 -0
- data/test/dummy/app/channels/application_cable/connection.rb +4 -0
- data/test/dummy/app/controllers/application_controller.rb +2 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/jobs/application_job.rb +2 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/models/application_record.rb +3 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +15 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +36 -0
- data/test/dummy/bin/update +31 -0
- data/test/dummy/bin/yarn +11 -0
- data/test/dummy/config/application.rb +20 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/cable.yml +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +32 -0
- data/test/dummy/config/environments/production.rb +57 -0
- data/test/dummy/config/environments/test.rb +33 -0
- data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/content_security_policy.rb +25 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/linkedin_sign_in.rb +4 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +33 -0
- data/test/dummy/config/puma.rb +34 -0
- data/test/dummy/config/routes.rb +2 -0
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/config/storage.yml +34 -0
- data/test/dummy/config.ru +5 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/package.json +5 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/test/dummy/public/apple-touch-icon.png +0 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/helpers/button_helper_test.rb +36 -0
- data/test/key.pem +27 -0
- data/test/models/identity_test.rb +48 -0
- data/test/models/redirect_protector_test.rb +34 -0
- data/test/test_helper.rb +28 -0
- metadata +267 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ad7912381b74e7f64e9bae51e0a684b300b34e2f4c41c85744cb610ff17607cc
|
4
|
+
data.tar.gz: 244c9cff9027b336a4d6bfbdd2028bd5673c1b9f1dc401d7781cdbae5e394a97
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 721a1b383a91a13737ed9ab1e01c4b9c655a1482cc61cd740ec6391004ad7021b6787a24b640a19a361cc4e73265af08062e04f60899389dc3e5b01d3cc921b9
|
7
|
+
data.tar.gz: 71c4e31c993787c14cd7e8ddcd2f1c27c5118e02226527adb5ef4a6a6355416768fa0ae9dccef47f49e247acd0de56ffbe867082b805b95253ba619c0fdc1b4c
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
language: ruby
|
2
|
+
sudo: false
|
3
|
+
cache: bundler
|
4
|
+
|
5
|
+
# Bundler/RubyGems incompat on Ruby 2.5.0
|
6
|
+
before_install: gem install bundler
|
7
|
+
|
8
|
+
rvm:
|
9
|
+
- 2.2
|
10
|
+
- 2.3
|
11
|
+
- 2.4
|
12
|
+
- 2.5
|
13
|
+
- ruby-head
|
14
|
+
|
15
|
+
matrix:
|
16
|
+
allow_failures:
|
17
|
+
- rvm: ruby-head
|
18
|
+
fast_finish: true
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
linkedin_sign_in (0.3)
|
5
|
+
oauth2 (>= 1.4.0)
|
6
|
+
rails (>= 5.2.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actioncable (5.2.1)
|
12
|
+
actionpack (= 5.2.1)
|
13
|
+
nio4r (~> 2.0)
|
14
|
+
websocket-driver (>= 0.6.1)
|
15
|
+
actionmailer (5.2.1)
|
16
|
+
actionpack (= 5.2.1)
|
17
|
+
actionview (= 5.2.1)
|
18
|
+
activejob (= 5.2.1)
|
19
|
+
mail (~> 2.5, >= 2.5.4)
|
20
|
+
rails-dom-testing (~> 2.0)
|
21
|
+
actionpack (5.2.1)
|
22
|
+
actionview (= 5.2.1)
|
23
|
+
activesupport (= 5.2.1)
|
24
|
+
rack (~> 2.0)
|
25
|
+
rack-test (>= 0.6.3)
|
26
|
+
rails-dom-testing (~> 2.0)
|
27
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
28
|
+
actionview (5.2.1)
|
29
|
+
activesupport (= 5.2.1)
|
30
|
+
builder (~> 3.1)
|
31
|
+
erubi (~> 1.4)
|
32
|
+
rails-dom-testing (~> 2.0)
|
33
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
34
|
+
activejob (5.2.1)
|
35
|
+
activesupport (= 5.2.1)
|
36
|
+
globalid (>= 0.3.6)
|
37
|
+
activemodel (5.2.1)
|
38
|
+
activesupport (= 5.2.1)
|
39
|
+
activerecord (5.2.1)
|
40
|
+
activemodel (= 5.2.1)
|
41
|
+
activesupport (= 5.2.1)
|
42
|
+
arel (>= 9.0)
|
43
|
+
activestorage (5.2.1)
|
44
|
+
actionpack (= 5.2.1)
|
45
|
+
activerecord (= 5.2.1)
|
46
|
+
marcel (~> 0.3.1)
|
47
|
+
activesupport (5.2.1)
|
48
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
49
|
+
i18n (>= 0.7, < 2)
|
50
|
+
minitest (~> 5.1)
|
51
|
+
tzinfo (~> 1.1)
|
52
|
+
addressable (2.5.2)
|
53
|
+
public_suffix (>= 2.0.2, < 4.0)
|
54
|
+
arel (9.0.0)
|
55
|
+
builder (3.2.3)
|
56
|
+
byebug (10.0.2)
|
57
|
+
concurrent-ruby (1.0.5)
|
58
|
+
crack (0.4.3)
|
59
|
+
safe_yaml (~> 1.0.0)
|
60
|
+
crass (1.0.4)
|
61
|
+
erubi (1.7.1)
|
62
|
+
faraday (0.15.3)
|
63
|
+
multipart-post (>= 1.2, < 3)
|
64
|
+
globalid (0.4.1)
|
65
|
+
activesupport (>= 4.2.0)
|
66
|
+
hashdiff (0.3.7)
|
67
|
+
i18n (1.1.1)
|
68
|
+
concurrent-ruby (~> 1.0)
|
69
|
+
jwt (2.1.0)
|
70
|
+
loofah (2.2.3)
|
71
|
+
crass (~> 1.0.2)
|
72
|
+
nokogiri (>= 1.5.9)
|
73
|
+
mail (2.7.1)
|
74
|
+
mini_mime (>= 0.1.1)
|
75
|
+
marcel (0.3.3)
|
76
|
+
mimemagic (~> 0.3.2)
|
77
|
+
method_source (0.9.1)
|
78
|
+
mimemagic (0.3.2)
|
79
|
+
mini_mime (1.0.1)
|
80
|
+
mini_portile2 (2.3.0)
|
81
|
+
minitest (5.11.3)
|
82
|
+
multi_json (1.13.1)
|
83
|
+
multi_xml (0.6.0)
|
84
|
+
multipart-post (2.0.0)
|
85
|
+
nio4r (2.3.1)
|
86
|
+
nokogiri (1.8.5)
|
87
|
+
mini_portile2 (~> 2.3.0)
|
88
|
+
oauth2 (1.4.1)
|
89
|
+
faraday (>= 0.8, < 0.16.0)
|
90
|
+
jwt (>= 1.0, < 3.0)
|
91
|
+
multi_json (~> 1.3)
|
92
|
+
multi_xml (~> 0.5)
|
93
|
+
rack (>= 1.2, < 3)
|
94
|
+
public_suffix (3.0.3)
|
95
|
+
rack (2.0.5)
|
96
|
+
rack-test (1.1.0)
|
97
|
+
rack (>= 1.0, < 3)
|
98
|
+
rails (5.2.1)
|
99
|
+
actioncable (= 5.2.1)
|
100
|
+
actionmailer (= 5.2.1)
|
101
|
+
actionpack (= 5.2.1)
|
102
|
+
actionview (= 5.2.1)
|
103
|
+
activejob (= 5.2.1)
|
104
|
+
activemodel (= 5.2.1)
|
105
|
+
activerecord (= 5.2.1)
|
106
|
+
activestorage (= 5.2.1)
|
107
|
+
activesupport (= 5.2.1)
|
108
|
+
bundler (>= 1.3.0)
|
109
|
+
railties (= 5.2.1)
|
110
|
+
sprockets-rails (>= 2.0.0)
|
111
|
+
rails-dom-testing (2.0.3)
|
112
|
+
activesupport (>= 4.2.0)
|
113
|
+
nokogiri (>= 1.6)
|
114
|
+
rails-html-sanitizer (1.0.4)
|
115
|
+
loofah (~> 2.2, >= 2.2.2)
|
116
|
+
railties (5.2.1)
|
117
|
+
actionpack (= 5.2.1)
|
118
|
+
activesupport (= 5.2.1)
|
119
|
+
method_source
|
120
|
+
rake (>= 0.8.7)
|
121
|
+
thor (>= 0.19.0, < 2.0)
|
122
|
+
rake (12.3.1)
|
123
|
+
safe_yaml (1.0.4)
|
124
|
+
sprockets (3.7.2)
|
125
|
+
concurrent-ruby (~> 1.0)
|
126
|
+
rack (> 1, < 3)
|
127
|
+
sprockets-rails (3.2.1)
|
128
|
+
actionpack (>= 4.0)
|
129
|
+
activesupport (>= 4.0)
|
130
|
+
sprockets (>= 3.0.0)
|
131
|
+
thor (0.20.0)
|
132
|
+
thread_safe (0.3.6)
|
133
|
+
tzinfo (1.2.5)
|
134
|
+
thread_safe (~> 0.1)
|
135
|
+
webmock (3.4.2)
|
136
|
+
addressable (>= 2.3.6)
|
137
|
+
crack (>= 0.3.2)
|
138
|
+
hashdiff
|
139
|
+
websocket-driver (0.7.0)
|
140
|
+
websocket-extensions (>= 0.1.0)
|
141
|
+
websocket-extensions (0.1.3)
|
142
|
+
|
143
|
+
PLATFORMS
|
144
|
+
ruby
|
145
|
+
|
146
|
+
DEPENDENCIES
|
147
|
+
bundler (~> 1.15)
|
148
|
+
byebug
|
149
|
+
jwt (>= 1.5.6)
|
150
|
+
linkedin_sign_in!
|
151
|
+
rake
|
152
|
+
webmock (>= 3.4.2)
|
153
|
+
|
154
|
+
BUNDLED WITH
|
155
|
+
1.16.4
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2018 Vincent Robert
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
This gem is shamlessly based on [Google SignIn by Basecamp](https://github.com/basecamp/google_sign_in).
|
2
|
+
|
3
|
+
# Linkedin Sign-In for Rails
|
4
|
+
|
5
|
+
This gem allows you to add Linkedin sign-in to your Rails app. You can let users sign up for and sign in to your service
|
6
|
+
with their Linkedin accounts.
|
7
|
+
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add `linkedin_sign_in` to your Rails app’s Gemfile and run `bundle install`:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'linkedin_sign_in'
|
15
|
+
```
|
16
|
+
|
17
|
+
Linkedin Sign-In for Rails requires Rails 5.2 or newer.
|
18
|
+
|
19
|
+
|
20
|
+
## Configuration
|
21
|
+
|
22
|
+
First, set up an OAuth 2.0 Client ID in the Linkedin API Console:
|
23
|
+
|
24
|
+
1. Go to the [Developer Portal](https://www.linkedin.com/developer/apps).
|
25
|
+
|
26
|
+
2. Create an application.
|
27
|
+
|
28
|
+
3. Submit your application information.
|
29
|
+
|
30
|
+
4. You are presented with a client ID and client secret. Save these.
|
31
|
+
|
32
|
+
5. This gem adds a single OAuth callback to your app at `/linkedin_sign_in/callback`. Under **Authorized Redirect URLs**,
|
33
|
+
add that callback for your application’s domain: for example, `https://example.com/linkedin_sign_in/callback`.
|
34
|
+
|
35
|
+
To use Linkedin sign-in in development, you’ll need to add another redirect URI for your local environment, like
|
36
|
+
`http://localhost:3000/linkedin_sign_in/callback`. For security reasons, we recommend using a separate
|
37
|
+
client ID for local development. Repeat these instructions to set up a new client ID for development.
|
38
|
+
|
39
|
+
6. Click the button labeled Update.
|
40
|
+
|
41
|
+
With your client ID set up, configure your Rails application to use it. Run `bin/rails credentials:edit` to edit your
|
42
|
+
app’s [encrypted credentials](https://guides.rubyonrails.org/security.html#custom-credentials) and add the following:
|
43
|
+
|
44
|
+
```yaml
|
45
|
+
linkedin_sign_in:
|
46
|
+
client_id: [Your client ID here]
|
47
|
+
client_secret: [Your client secret here]
|
48
|
+
```
|
49
|
+
|
50
|
+
You’re all set to use Linkedin sign-in now. The gem automatically uses the client ID and client secret in your credentials.
|
51
|
+
|
52
|
+
Alternatively, you can provide the client ID and client secret using ENV variables. Add a new initializer that sets
|
53
|
+
`config.linkedin_sign_in.client_id` and `config.linkedin_sign_in.client_secret`:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
# config/initializers/linkedin_sign_in.rb
|
57
|
+
Rails.application.configure do
|
58
|
+
config.linkedin_sign_in.client_id = ENV['linkedin_sign_in_client_id']
|
59
|
+
config.linkedin_sign_in.client_secret = ENV['linkedin_sign_in_client_secret']
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
**⚠️ Important:** Take care to protect your client secret from disclosure to third parties.
|
64
|
+
|
65
|
+
|
66
|
+
## Usage
|
67
|
+
|
68
|
+
This gem provides a `linkedin_sign_in_button` helper. It generates a button which initiates Linkedin sign-in:
|
69
|
+
|
70
|
+
```erb
|
71
|
+
<%= linkedin_sign_in_button 'Sign in with my Linkedin account', proceed_to: create_login_url %>
|
72
|
+
|
73
|
+
<%= linkedin_sign_in_button image_tag('linkedin_logo.png', alt: 'Linkedin'), proceed_to: create_login_url %>
|
74
|
+
|
75
|
+
<%= linkedin_sign_in_button proceed_to: create_login_url do %>
|
76
|
+
Sign in with my <%= image_tag('linkedin_logo.png', alt: 'Linkedin') %> account
|
77
|
+
<% end %>
|
78
|
+
```
|
79
|
+
|
80
|
+
The `proceed_to` argument is required. After authenticating with Linkedin, the gem redirects to `proceed_to`, providing
|
81
|
+
a Linkedin ID token in `flash[:linkedin_sign_in_token]`. Your application decides what to do with it:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
# config/routes.rb
|
85
|
+
Rails.application.routes.draw do
|
86
|
+
# ...
|
87
|
+
get 'login', to: 'logins#new'
|
88
|
+
get 'login/create', to: 'logins#create', as: :create_login
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
# app/controllers/logins_controller.rb
|
94
|
+
class LoginsController < ApplicationController
|
95
|
+
def new
|
96
|
+
end
|
97
|
+
|
98
|
+
def create
|
99
|
+
if user = authenticate_with_linkedin
|
100
|
+
cookies.signed[:user_id] = user.id
|
101
|
+
redirect_to user
|
102
|
+
else
|
103
|
+
redirect_to new_session_url, alert: 'authentication_failed'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
def authenticate_with_linkedin
|
109
|
+
if flash[:linkedin_sign_in_token].present?
|
110
|
+
User.find_by linkedin_id: LinkedinSignIn::Identity.new(flash[:linkedin_sign_in_token]).user_id
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
(The above example assumes the user has already signed up for your service and that you’re storing their Linkedin user ID
|
117
|
+
in the `User#linkedin_id` attribute.)
|
118
|
+
|
119
|
+
For security reasons, the `proceed_to` URL you provide to `linkedin_sign_in_button` is required to reside on the same
|
120
|
+
origin as your application. This means it must have the same protocol, host, and port as the page where
|
121
|
+
`linkedin_sign_in_button` is used. We enforce this before redirecting to the `proceed_to` URL to guard against
|
122
|
+
[open redirects](https://www.owasp.org/index.php/Unvalidated_Redirects_and_Forwards_Cheat_Sheet).
|
123
|
+
|
124
|
+
### `LinkedinSignIn::Identity`
|
125
|
+
|
126
|
+
The `LinkedinSignIn::Identity` class decodes and verifies the integrity of a Linkedin ID token. It exposes the profile
|
127
|
+
information contained in the token via the following instance methods:
|
128
|
+
|
129
|
+
* `name`
|
130
|
+
|
131
|
+
* `email_address`
|
132
|
+
|
133
|
+
* `user_id`: A string that uniquely identifies a single Linkedin user. Use this, not `email_address`, to associate a
|
134
|
+
Linkedin user with an application user. A Linkedin user’s email address may change, but their `user_id` will remain constant.
|
135
|
+
|
136
|
+
* `email_verified?`
|
137
|
+
|
138
|
+
* `avatar_url`
|
139
|
+
|
140
|
+
* `locale`
|
141
|
+
|
142
|
+
* `hosted_domain`: The user’s hosted G Suite domain, provided only if they belong to a G Suite.
|
143
|
+
|
144
|
+
|
145
|
+
## Security
|
146
|
+
|
147
|
+
For information on our security response procedure, see [SECURITY.md](SECURITY.md).
|
148
|
+
|
149
|
+
|
150
|
+
## License
|
151
|
+
|
152
|
+
Linkedin Sign-In for Rails is released under the [MIT License](https://opensource.org/licenses/MIT).
|
153
|
+
|
154
|
+
Linkedin is a registered trademark of Linkedin LLC. This project is not operated by or in any way affiliated with Linkedin LLC.
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
require "rake/testtask"
|
4
|
+
|
5
|
+
Rake::TestTask.new do |test|
|
6
|
+
test.libs << "test"
|
7
|
+
test.test_files = FileList["test/**/*_test.rb"]
|
8
|
+
test.warning = false
|
9
|
+
end
|
10
|
+
|
11
|
+
task default: :test
|
12
|
+
|
13
|
+
desc "Generates an X509 certificate for decoding test ID tokens"
|
14
|
+
task "test:certificate:generate" do
|
15
|
+
require "openssl"
|
16
|
+
require "active_support"
|
17
|
+
require "active_support/core_ext/integer/time"
|
18
|
+
|
19
|
+
key = OpenSSL::PKey::RSA.new(File.read(File.expand_path("test/key.pem", __dir__)))
|
20
|
+
|
21
|
+
certificate = OpenSSL::X509::Certificate.new
|
22
|
+
certificate.subject = certificate.issuer = OpenSSL::X509::Name.parse("/CN=linkedin-sign-in-for-rails.example.com")
|
23
|
+
certificate.not_before = Time.now
|
24
|
+
certificate.not_after = 5.years.from_now
|
25
|
+
certificate.public_key = key.public_key
|
26
|
+
certificate.serial = 0
|
27
|
+
certificate.version = 1
|
28
|
+
|
29
|
+
extension_factory = OpenSSL::X509::ExtensionFactory.new
|
30
|
+
extension_factory.subject_certificate = certificate
|
31
|
+
extension_factory.issuer_certificate = certificate
|
32
|
+
certificate.extensions = [
|
33
|
+
extension_factory.create_extension("basicConstraints", "CA:FALSE", true),
|
34
|
+
extension_factory.create_extension("keyUsage", "digitalSignature", true),
|
35
|
+
extension_factory.create_extension("extendedKeyUsage", "clientAuth", true)
|
36
|
+
]
|
37
|
+
|
38
|
+
certificate.sign(key, OpenSSL::Digest::SHA1.new)
|
39
|
+
File.write(File.expand_path("test/certificate.pem", __dir__), certificate.to_pem)
|
40
|
+
end
|
data/SECURITY.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
class LinkedinSignIn::AuthorizationsController < LinkedinSignIn::BaseController
|
4
|
+
def create
|
5
|
+
redirect_to login_url(scope: 'r_basicprofile r_emailaddress', state: state),
|
6
|
+
flash: { proceed_to: params.require(:proceed_to), state: state }
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
def login_url(**params)
|
11
|
+
client.auth_code.authorize_url(prompt: 'login', **params)
|
12
|
+
end
|
13
|
+
|
14
|
+
def state
|
15
|
+
@state ||= SecureRandom.base64(24)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'oauth2'
|
2
|
+
|
3
|
+
class LinkedinSignIn::BaseController < ActionController::Base
|
4
|
+
protect_from_forgery with: :exception
|
5
|
+
|
6
|
+
private
|
7
|
+
def client
|
8
|
+
@client ||= OAuth2::Client.new \
|
9
|
+
LinkedinSignIn.client_id,
|
10
|
+
LinkedinSignIn.client_secret,
|
11
|
+
authorize_url: 'https://www.linkedin.com/oauth/v2/authorization',
|
12
|
+
token_url: 'https://www.linkedin.com/oauth/v2/accessToken',
|
13
|
+
redirect_uri: callback_url
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_dependency 'linkedin_sign_in/redirect_protector'
|
2
|
+
|
3
|
+
class LinkedinSignIn::CallbacksController < LinkedinSignIn::BaseController
|
4
|
+
def show
|
5
|
+
if valid_request?
|
6
|
+
redirect_to proceed_to_url, flash: { linkedin_sign_in_token: token }
|
7
|
+
else
|
8
|
+
head :unprocessable_entity
|
9
|
+
end
|
10
|
+
rescue LinkedinSignIn::RedirectProtector::Violation => error
|
11
|
+
logger.error error.message
|
12
|
+
head :bad_request
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def valid_request?
|
17
|
+
flash[:state].present? && params.require(:state) == flash[:state] && params[:error].blank?
|
18
|
+
end
|
19
|
+
|
20
|
+
def proceed_to_url
|
21
|
+
flash[:proceed_to].tap { |url| LinkedinSignIn::RedirectProtector.ensure_same_origin(url, request.url) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def token
|
25
|
+
client.auth_code.get_token(params.require(:code)).token
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module LinkedinSignIn::ButtonHelper
|
2
|
+
def linkedin_sign_in_button(text = nil, proceed_to:, **options, &block)
|
3
|
+
form_with url: linkedin_sign_in.authorization_path, local: true do
|
4
|
+
hidden_field_tag(:proceed_to, proceed_to, id: nil) + button_tag(text, name: nil, **options, &block)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
data/bin/rails
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails gems
|
3
|
+
# installed from the root of your application.
|
4
|
+
|
5
|
+
ENGINE_ROOT = File.expand_path('..', __dir__)
|
6
|
+
ENGINE_PATH = File.expand_path('../lib/blorgh/engine', __dir__)
|
7
|
+
APP_PATH = File.expand_path('../test/dummy/config/application', __dir__)
|
8
|
+
|
9
|
+
# Set up gems listed in the Gemfile.
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
11
|
+
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
12
|
+
|
13
|
+
require 'rails'
|
14
|
+
require 'action_controller/railtie'
|
15
|
+
require 'rails/test_unit/railtie'
|
16
|
+
require 'rails/engine/commands'
|
data/config/routes.rb
ADDED