Skip to content

Commit

Permalink
Login oauth workaround (#33)
Browse files Browse the repository at this point in the history
* finished adding API key to form

* worked oauth into the app

* fix tests

* pushing secrets for travis

* updated tarfile
  • Loading branch information
adnanhemani authored Mar 29, 2019
1 parent b1f1600 commit 64fdea3
Show file tree
Hide file tree
Showing 19 changed files with 236 additions and 12 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
.DS_Store

credentials.json
credentials_oauth.json

token.yaml

Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ gem 'pivotal-tracker'
gem 'backtop'
gem 'bson_ext'
gem 'google-api-client', '~> 0.8'
gem "omniauth-google-oauth2"
gem 'omniauth-oauth2', '~> 1.3.1'

gem 'rspec-rails', '~> 3.6.1', group: [:test, :development]

Expand Down
19 changes: 19 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ GEM
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (~> 0.7)
hashie (3.6.0)
http-cookie (1.0.3)
domain_name (~> 0.5)
http_parser.rb (0.6.0)
Expand Down Expand Up @@ -213,13 +214,29 @@ GEM
metaclass (~> 0.0.1)
multi_json (1.13.1)
multi_test (0.1.2)
multi_xml (0.6.0)
multipart-post (2.0.0)
netrc (0.11.0)
newrelic_rpm (6.0.0.351)
nokogiri (1.10.1)
mini_portile2 (~> 2.4.0)
nokogiri-happymapper (0.6.0)
nokogiri (~> 1.5)
oauth2 (1.4.1)
faraday (>= 0.8, < 0.16.0)
jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
omniauth (1.9.0)
hashie (>= 3.4.6, < 3.7.0)
rack (>= 1.6.2, < 3)
omniauth-google-oauth2 (0.2.6)
omniauth (> 1.0)
omniauth-oauth2 (~> 1.1)
omniauth-oauth2 (1.3.1)
oauth2 (~> 1.0)
omniauth (~> 1.2)
os (1.0.0)
pg (0.21.0)
pivotal-tracker (0.5.13)
Expand Down Expand Up @@ -407,6 +424,8 @@ DEPENDENCIES
json
mocha
newrelic_rpm
omniauth-google-oauth2
omniauth-oauth2 (~> 1.3.1)
pg (~> 0.21)
pivotal-tracker
rack_session_access
Expand Down
Binary file added app/assets/images/sign_in_google_button.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions app/assets/stylesheets/application.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -380,4 +380,8 @@ body {
padding: 20px 30px;
}
}
}

.font-size-lg {
font-size:18px;
}
37 changes: 31 additions & 6 deletions app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,37 @@ def new

def create
user = User.authenticate(session_params)
create_session_helper(user, t('flashes.sessions.failed'))
end

def destroy
reset_session
redirect_to :login, notice: t('flashes.sessions.destroy')
end

def new_api_key
redirect_to :root if user_signed_in?
end

def set_api_key
# Take email and API key, set new user
# Then redirect to login with success flash noting that API key saved
if params[:api_key].blank? or params[:username].blank?
redirect_to :new_api_key, alert: t('flashes.sessions.token_not_set')
else
User.set_new_api_key(params)
redirect_to :login, notice: t('flashes.sessions.token_set')
end
end

def google_oauth_login
# Find out which user logged in successfully
# Set session, then redirect to root
this_user = User.authenticate_after_oauth(env["omniauth.auth"]["info"]["email"])
create_session_helper(this_user, t('flashes.sessions.without_token'))
end

def create_session_helper(user, potential_failure_msg)
if user
session[:user] = {
username: user.username,
Expand All @@ -15,15 +45,10 @@ def create

redirect_to :root, notice: t('flashes.sessions.success')
else
redirect_to :login, alert: t('flashes.sessions.failed')
redirect_to :login, alert: potential_failure_msg
end
end

def destroy
reset_session
redirect_to :login, notice: t('flashes.sessions.destroy')
end

private

def session_params
Expand Down
24 changes: 24 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,30 @@ def salted(username)
def encrypt(password, salt)
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
end

def set_new_api_key(params)
this_user = User.find_by_username(params[:username])
if not this_user
this_user = User.new(
username: params[:username],
password: (0...8).map { (65 + rand(26)).chr }.join,
token: params[:api_key]
)
else
this_user.token = params[:api_key]
end
this_user.save!
end

def authenticate_after_oauth(username)
# Returns user if found and has API token, nil if not
this_user = User.find_by_username(username)
if this_user and not this_user.token.empty?
this_user
else
nil
end
end
end

# Checks passwords against crypted password
Expand Down
16 changes: 15 additions & 1 deletion app/views/sessions/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,18 @@
</div>

<%= submit_tag t('signin').upcase, class: 'btn btn-success' %>
<% end %>
<% end %>

<br>
<br>

<div class='col-md-15 text-left font-size-lg'>
<!-- Sign in with Google -->
<%= link_to "/auth/google_oauth2" do %>
<%= image_tag('sign_in_google_button.png') %>
<% end %>
<br><br>
<!-- Set API Key -->
<p>First time signing in with Google? Set your API token below.</p>
<%= button_to "Set API Token", new_api_key_path, method: :get, class: 'btn btn-success' %>
</div>
24 changes: 24 additions & 0 deletions app/views/sessions/new_api_key.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<div id="signin-box">
<h1>
Pivotal Tracker
</h1>
<div class='col-md-15 text-left font-size-lg'>
<p1>You only need to set your API key once (or if you have had to change your password).</p1><br>
<p1>This is only required for Google OAuth users. Regular users with passwords do not need to fill this form out. Proceed to the Login screen as normal to sign in.</p1><br><br>
<p1>For information on how to access your API key, <%= link_to "click this link", "https://www.pivotaltracker.com/help/articles/api_token/" %> .</p1>
</div>
<br>

<%= form_tag set_api_key_path, as: :session do %>

<div class="form-group">
<%= text_field_tag :username, nil, class: 'form-control', placeholder: 'Email / Username' %>
</div>

<div class="form-group">
<%= password_field_tag :api_key, nil, class: 'form-control', placeholder: 'API Key' %>
</div>

<%= submit_tag t('setapikey').upcase, class: 'btn btn-success' %>
<% end %>
</div>
9 changes: 9 additions & 0 deletions config/initializers/omniauth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require 'json'

OmniAuth.config.logger = Rails.logger
google_data = JSON.parse(File.read('credentials_oauth.json'))["web"]


Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_oauth2, google_data["client_id"], google_data["client_secret"]#, {client_options: {ssl: {ca_file: Rails.root.join("cacert.pem").to_s}}}
end
4 changes: 4 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ en:
reveal: "Reveal"
save: "Save"
signin: "Sign In"
setapikey: "Set API Key"
signout: "Sign Out"
story: "Story"
unestimated: "Unestimated"
Expand Down Expand Up @@ -45,6 +46,9 @@ en:
signin: "You will need to sign in first"
success: "You have successfully logged in"
unauthorized: "No API Key / Token found. Please re-login!"
token_set: "Your API Key has been successfully set!"
token_not_set: "Your API Key wasn't set. Please try again."
without_token: "You're using an account without an API token set. Please check your account or make sure you have an API token set"

stories:
update: "Story ID#%{id} has been updated successfully"
5 changes: 5 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
Rails.application.routes.draw do
root to: 'dashboard#index'

get 'auth/:provider/callback', to: 'sessions#google_oauth_login'
get 'auth/failure', to: 'sessions#new'

get 'favicon.ico', controller: :application, action: :favicon

controller :sessions do
get :login, action: :new
post :login, action: :create
delete :logout, action: :destroy
get :new_api_key, action: :new_api_key
post :new_api_key, action: :set_api_key, as: :set_api_key
end

resources :dashboard, only: [:index]
Expand Down
Binary file modified db/development
Binary file not shown.
Binary file modified db/test
Binary file not shown.
Binary file modified secrets.tar.enc
Binary file not shown.
7 changes: 5 additions & 2 deletions spec/controllers/dashboard_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,11 @@ def valid_session

before do
$service = mock("$service")
$service.stubs(:insert_event).returns({:id => "abcd"})
end
$service.stubs(:insert_event).returns(OpenStruct.new({:id => "abcd"}))
request_options_mock = mock()
$service.stubs(:request_options).returns(request_options_mock)
request_options_mock.stubs(:retries=)
end

it "should call on Project#create_hangout" do
Project.expects(:create_hangout)
Expand Down
40 changes: 39 additions & 1 deletion spec/controllers/sessions_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ def valid_session
end

describe 'GET new' do

it 'should redirect to root' do
get :new, {}, valid_session
expect(response).to redirect_to root_path
Expand Down Expand Up @@ -75,4 +74,43 @@ def valid_session
end
end

describe 'GET new_api_key' do
it 'should redirect to root' do
get :new_api_key, {}, valid_session
expect(response).to redirect_to root_path
end
end

describe 'POST new_api_key' do
let(:params) {{
'username' => user.username,
'api_key' => "abcdtestrandomchars"
}}

it 'should create a new user if one does not currently exist if successful' do
post :set_api_key, params, valid_session
expect(response).to redirect_to login_path
end

it 'should not create new user if not successful' do
post :set_api_key, {'username' => "",'api_key' => ""}, valid_session
expect(response).to redirect_to new_api_key_path
end
end

# How do we even get around this??
# describe 'GET auth/:provider/callback' do
# it 'should log in a user if we have the API tokens for this user' do
# User.stubs(:authenticate_after_oauth).returns(user)
# get oauth_callback_path("google_oauth"), {}, valid_session
# expect(response).to redirect_to root_path
# end

# it 'should not log in a user if we do not have API tokens for this user' do
# User.stubs(:authenticate_after_oauth).returns(nil)
# get :google_oauth_login, {}, valid_session
# expect(response).to redirect_to login_path
# end
# end

end
8 changes: 6 additions & 2 deletions spec/models/project_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
before do
Project.delete_all
$service = mock("$service")
$service.stubs(:insert_event).returns({:id => "abcd"})
request_options_mock = mock()
$service.stubs(:request_options).returns(request_options_mock)
request_options_mock.stubs(:retries=)
$service.stubs(:insert_event).returns(OpenStruct.new({:id => "abcd"}))
end
let(:project_id) { "some_id" }
context "#create_hangout" do
Expand All @@ -13,7 +16,8 @@
Project.create_hangout(:project_id)
end
it "locks before calling API" do
Project.any_instance.expects(:event_id=).with("LOCKED")
Project.any_instance.expects(:event_id=).at_least(1).with("LOCKED")
Project.any_instance.expects(:event_id=).at_most(1).with("abcd")
Project.create_hangout(:project_id)
end
it "creates new project with event" do
Expand Down
Loading

0 comments on commit 64fdea3

Please sign in to comment.