-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GT-1839, implement facebook auth #1228
Merged
Merged
Changes from 46 commits
Commits
Show all changes
51 commits
Select commit
Hold shift + click to select a range
67823be
implement facebook auth
andrewroth 9832d44
standardrb fixes, rack update
andrewroth a492c19
match users based on facebook user id
andrewroth d36f9c5
remove rescue for bad request, it's not an exception but a reponse type
andrewroth 9b95d15
move facebook code to service to match okta code style
andrewroth 9385ce1
standardrb fixes
andrewroth 5b7f6a4
handle json parse error instead of jwt decode which never happens in …
andrewroth 2b515c5
add test for json error
andrewroth 4b67af7
remove useless assignment variable
andrewroth c25b937
implement facebook user delete
andrewroth 039f596
standardrb fixes
andrewroth 3d9d46f
switch to account prefix url
andrewroth 45a31f1
track gr_master_person_id from okta
andrewroth 60f691b
use proper query escaping
andrewroth 5685516
security upgrades
andrewroth 1f868c7
Merge branch 'master' into GT-1839-support-facebook-logins
andrewroth a330241
Update app/controllers/deletion_requests_controller.rb
andrewroth 843cf69
Update app/services/facebook.rb
andrewroth 7131cdb
various tweaks as per code review
andrewroth 07aa6c1
add google auth
andrewroth 630a73f
style fix
andrewroth fb2fed1
implement apple token verify
andrewroth 5f766c4
Reference the PR that needs to be released for apple_auth
frett bc06ad5
use the validation from the apple library for the token issuer
andrewroth 0d00606
Merge branch 'GT-1839-support-facebook-logins' of github.com:CruGloba…
andrewroth 6c4a50c
refactor auth services to a base for common patterns
andrewroth 9d744fd
standardrb fixes
andrewroth 3ef394a
implement GT-1871, tracking name and using given_name & family_name
andrewroth 00b1bf3
standardrb fixes
andrewroth 7a69e27
Merge branch 'master' into GT-1839-support-facebook-logins
andrewroth 979619d
fix validate line and fix test failing because of expired token
andrewroth c7beec2
style fixes
andrewroth b5f54be
rename apple and google user identifiers to id_token
andrewroth 0c822e3
rename some methods to reflect token from google and apple is id_token
andrewroth ea4b609
handle apple and google passing in *_id_token instead of access_token
andrewroth 102f39b
rename auth service classes to be consistent
andrewroth e08df12
style fix
andrewroth 003a14c
fix tests
andrewroth 1b4ab2f
try to incrase coverage; don't need interface error messages now
andrewroth 4137c79
trying to get coverage up
andrewroth 4eb63a7
JWT::ExpiredSignature is a JWT::DecodeError, so it's redundant to cap…
andrewroth d41b11b
styling fixes
andrewroth ab42ea8
update schema
andrewroth d987a99
pull body from response
andrewroth 1ffdcb9
Merge branch 'GT-1839-support-facebook-logins' of github.com:CruGloba…
andrewroth 2ba0255
remove email unique requirement
andrewroth 5e2052f
Update app/services/okta_auth_service.rb
andrewroth bbbd3a2
tweak okta_auth_service to be more consistent on using primary_key
andrewroth 51f0667
don't need google service_name, now with the new class default is ok
andrewroth ae392dc
rename AuthServiceBase to BaseAuthService
andrewroth f77477e
add back the raise stubs for implementing classes
andrewroth File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
class DeletionRequestsController < ApplicationController | ||
# disable CSRF protection, as it doesn't make sense in this case | ||
protect_from_forgery with: :null_session | ||
|
||
def facebook | ||
begin | ||
dr = DeletionRequest.from_signed_fb(params["signed_request"]) | ||
rescue DeletionRequest::FailedAuthentication => e | ||
render json: {"error" => e.to_s} | ||
return | ||
end | ||
|
||
dr.run | ||
|
||
render json: { | ||
url: deletion_request_url(dr.pid), | ||
confirmation_code: dr.pid | ||
} | ||
end | ||
|
||
def show | ||
dr = DeletionRequest.find_by!(pid: params[:id]) | ||
render json: {"data" => dr.deleted? ? "Your data has been completely deleted" : "Your deletion request is still in progress"} | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
class DeletionRequest < ApplicationRecord | ||
validates_presence_of :uid, :provider, :pid | ||
|
||
# there can only be one entry with given provider + uid | ||
validates_uniqueness_of :uid, scope: :provider | ||
|
||
before_validation :set_pid | ||
|
||
def run | ||
associated_user&.destroy! | ||
end | ||
|
||
def deleted? | ||
associated_user.nil? | ||
end | ||
|
||
def self.from_signed_fb(req) | ||
encoded, payload = req.split(".", 2) | ||
decoded = Base64.urlsafe_decode64(encoded) | ||
data = JSON.parse(Base64.urlsafe_decode64(payload)) | ||
|
||
# we need to verify the digest is the same | ||
exp = OpenSSL::HMAC.digest("SHA256", ENV["FACEBOOK_APP_SECRET"], payload) | ||
raise FailedAuthentication, "FB deletion callback called with invalid data" if decoded != exp | ||
|
||
return unless data | ||
DeletionRequest.create(provider: "facebook", uid: data["user_id"]) | ||
end | ||
|
||
private | ||
|
||
def associated_user | ||
case provider | ||
when "facebook" | ||
User.find_by(facebook_user_id: uid) | ||
end | ||
end | ||
|
||
def set_pid | ||
if pid.blank? | ||
self.pid = SecureRandom.hex(4) | ||
end | ||
end | ||
|
||
class FailedAuthentication < StandardError | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,8 @@ | ||
class User < ApplicationRecord | ||
has_many :user_counters | ||
has_many :favorite_tools | ||
has_many :user_counters, dependent: :destroy | ||
has_many :favorite_tools, dependent: :destroy | ||
has_many :tools, through: :favorite_tools | ||
|
||
validates :sso_guid, uniqueness: true, presence: true | ||
|
||
# while the email needs to be validated case-insensitively, we'll | ||
# let Rails pass the insensitive check down to postgres's citext type | ||
validates :email, uniqueness: {case_sensitive: true}, presence: true | ||
validates :sso_guid, uniqueness: true, presence: true, unless: -> { facebook_user_id.present? || google_user_id.present? || apple_user_id.present? } | ||
validates :email, presence: true | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# frozen_string_literal: true | ||
|
||
class AppleAuthService < AuthServiceBase | ||
class << self | ||
def find_user_by_token(apple_id_token, apple_given_name = nil, apple_family_name = nil) | ||
decoded_token = decode_token(apple_id_token) | ||
validate_token!(apple_id_token, decoded_token) | ||
validate_expected_fields!(decoded_token) | ||
|
||
apple_id_token = remote_user_id(decoded_token) | ||
user_atts = extract_user_atts(apple_id_token, decoded_token, apple_id_token) | ||
user_atts["first_name"] = apple_given_name if apple_given_name.present? | ||
user_atts["last_name"] = apple_family_name if apple_family_name.present? | ||
setup_user(apple_id_token, user_atts) | ||
rescue JSON::ParserError => e | ||
raise FailedAuthentication, e.message | ||
rescue JWT::DecodeError => e | ||
raise FailedAuthentication, e.message | ||
rescue AppleAuth::Conditions::JWTValidationError => e | ||
raise FailedAuthentication, e.message | ||
end | ||
|
||
private | ||
|
||
def expected_fields | ||
%w[sub email iss aud] | ||
end | ||
|
||
def decode_token(apple_id_token) | ||
AppleAuth::JWTDecoder.new(apple_id_token).call | ||
end | ||
|
||
def validate_token!(apple_id_token, decoded_token) | ||
raise FailedAuthentication, "Sub is missing from payload" unless decoded_token["sub"] | ||
AppleAuth::UserIdentity.new(decoded_token["sub"], apple_id_token).validate! | ||
frett marked this conversation as resolved.
Show resolved
Hide resolved
|
||
end | ||
|
||
def remote_user_id(decoded_token) | ||
decoded_token["sub"] | ||
end | ||
|
||
def extract_user_atts(_apple_id_token, decoded_token, remote_user_id) | ||
{ | ||
apple_user_id: remote_user_id, | ||
email: decoded_token["email"] | ||
}.with_indifferent_access | ||
end | ||
end | ||
|
||
class FailedAuthentication < AuthServiceBase::FailedAuthentication | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# frozen_string_literal: true | ||
|
||
class AuthServiceBase | ||
knutsenm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
include HTTParty | ||
|
||
class << self | ||
def find_user_by_token(access_token) | ||
decoded_token = decode_token(access_token) | ||
knutsenm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
validate_token!(access_token, decoded_token) | ||
validate_expected_fields!(decoded_token) | ||
|
||
user_atts = extract_user_atts(access_token, decoded_token) | ||
setup_user(remote_user_id(decoded_token), user_atts) | ||
rescue JSON::ParserError => e | ||
raise self::FailedAuthentication, e.message | ||
rescue JWT::DecodeError => e | ||
raise self::FailedAuthentication, e.message | ||
end | ||
|
||
private | ||
|
||
def validate_expected_fields!(decoded_token) | ||
unless decoded_token.present? && decoded_token.is_a?(Hash) && decoded_token.keys.to_set.superset?(expected_fields.to_set) | ||
raise FailedAuthentication, "Error validating #{service_name} access_token: Missing some or all user fields (got #{decoded_token.keys.join(", ")}, expected #{expected_fields.join(", ")})" | ||
end | ||
end | ||
|
||
def setup_user(remote_user_id, user_atts) | ||
user = User.where(primary_key => remote_user_id).first_or_initialize | ||
user.update!(user_atts) | ||
user | ||
end | ||
|
||
def service_name | ||
name.gsub("AuthService", "").downcase | ||
end | ||
|
||
def primary_key | ||
:"#{service_name}_user_id" | ||
end | ||
end | ||
|
||
class FailedAuthentication < StandardError | ||
end | ||
end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No real action point here, but just letting you know that the
AccessCode
logic has been slated to be removed from mobile-content-api since November 2021. See GT-1348