Skip to content
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

Merge to master: Release 2.3.3 - Multi provider auth #44

Merged
merged 2 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ tmp/*
# Editor temp files
*.swp
*.swo
test/solr
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ gem 'rake', '~> 10.0'
gem 'sinatra', '~> 1.0'
gem 'sinatra-advanced-routes'
gem 'sinatra-contrib', '~> 1.0'
gem 'request_store'

# Rack middleware
gem 'ffi'
Expand Down
47 changes: 25 additions & 22 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
GIT
remote: https://github.com/ncbo/ncbo_ontology_recommender.git
revision: f440ae855a217807fead1d20629a0f187997b973
revision: 013abea4af3b10910ec661dbb358a4b6cae198a4
branch: master
specs:
ncbo_ontology_recommender (0.0.1)
Expand All @@ -11,7 +11,7 @@ GIT

GIT
remote: https://github.com/ontoportal-lirmm/goo.git
revision: bd7154217438c3b9160e0e9b495c7c718b55fbf8
revision: 74ea47defc7f6260b045a6c6997bbe6a59c7bf62
branch: master
specs:
goo (0.0.2)
Expand Down Expand Up @@ -53,7 +53,7 @@ GIT

GIT
remote: https://github.com/ontoportal-lirmm/ontologies_linked_data.git
revision: f44f7baa96eb3ee10dfab4a8aca154161ba7dd89
revision: 80a331d053ea04397a903452288c2186822c340c
branch: master
specs:
ontologies_linked_data (0.0.1)
Expand Down Expand Up @@ -108,7 +108,8 @@ GEM
airbrussh (1.5.0)
sshkit (>= 1.6.1, != 1.7.0)
backports (3.24.1)
bcrypt (3.1.19)
base64 (0.2.0)
bcrypt (3.1.20)
bcrypt_pbkdf (1.1.0)
bigdecimal (1.4.2)
builder (3.2.4)
Expand All @@ -130,11 +131,10 @@ GEM
rexml
cube-ruby (0.0.3)
dante (0.2.0)
date (3.3.3)
date (3.3.4)
declarative (0.0.20)
docile (1.4.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
domain_name (0.6.20231109)
ed25519 (1.3.0)
faraday (1.10.3)
faraday-em_http (~> 1.0)
Expand Down Expand Up @@ -164,7 +164,7 @@ GEM
ffi (~> 1.0)
google-apis-analytics_v3 (0.13.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.1)
google-apis-core (0.11.2)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
Expand All @@ -189,14 +189,14 @@ GEM
httpclient (2.8.3)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
json (2.6.3)
json (2.7.1)
json-schema (2.8.1)
addressable (>= 2.4)
json_pure (2.6.3)
json_pure (2.7.1)
jwt (2.7.1)
kgio (2.11.4)
libxml-ruby (4.1.1)
logger (1.5.3)
libxml-ruby (4.1.2)
logger (1.6.0)
macaddr (1.7.2)
systemu (~> 2.6.5)
mail (2.8.1)
Expand All @@ -216,20 +216,21 @@ GEM
multi_json (1.15.0)
multipart-post (2.3.0)
net-http-persistent (2.9.4)
net-imap (0.4.1)
net-imap (0.4.7)
date
net-protocol
net-pop (0.1.2)
net-protocol
net-protocol (0.2.1)
net-protocol (0.2.2)
timeout
net-scp (4.0.0)
net-ssh (>= 2.6.5, < 8.0.0)
net-smtp (0.4.0)
net-protocol
net-ssh (7.2.0)
netrc (0.11.0)
newrelic_rpm (9.5.0)
newrelic_rpm (9.6.0)
base64
oj (2.18.5)
omni_logger (0.1.4)
logger
Expand All @@ -240,7 +241,7 @@ GEM
pry (0.14.2)
coderay (~> 1.1)
method_source (~> 1.0)
public_suffix (5.0.3)
public_suffix (5.0.4)
rack (1.6.13)
rack-accept (0.4.5)
rack (>= 0.4)
Expand Down Expand Up @@ -275,6 +276,8 @@ GEM
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
request_store (1.5.1)
rack (>= 1.4)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
Expand Down Expand Up @@ -317,20 +320,17 @@ GEM
rack-test
sinatra (~> 1.4.0)
tilt (>= 1.3, < 3)
sshkit (1.21.5)
sshkit (1.21.6)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
systemu (2.6.5)
temple (0.10.3)
tilt (2.3.0)
timeout (0.4.0)
timeout (0.4.1)
trailblazer-option (0.1.2)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicorn (6.1.0)
kgio (~> 2.6)
raindrops (~> 0.7)
Expand All @@ -346,6 +346,8 @@ GEM
webrick (1.8.1)

PLATFORMS
x86_64-darwin-21
x86_64-darwin-23
x86_64-linux

DEPENDENCIES
Expand Down Expand Up @@ -389,6 +391,7 @@ DEPENDENCIES
redis-activesupport
redis-rack-cache (~> 2.0)
redis-store (= 1.9.1)
request_store
shotgun!
simplecov
simplecov-cobertura
Expand All @@ -401,4 +404,4 @@ DEPENDENCIES
webmock

BUNDLED WITH
2.3.23
2.4.21
18 changes: 18 additions & 0 deletions config/environments/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,24 @@
"apikey" => "1cfae05f-9e67-486f-820b-b393dec5764b"
}
}
config.oauth_providers = {
github: {
check: :access_token,
link: 'https://api.github.com/user'
},
keycloak: {
check: :jwt_token,
cert: 'KEYCLOAK_SECRET_KEY'
},
orcid: {
check: :access_token,
link: 'https://pub.orcid.org/v3.0/me'
},
google: {
check: :access_token,
link: 'https://www.googleapis.com/oauth2/v3/userinfo'
}
}
end

Annotator.config do |config|
Expand Down
48 changes: 17 additions & 31 deletions controllers/users_controller.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
class UsersController < ApplicationController
namespace "/users" do
post "/authenticate" do
user_id = params["user"]
user_password = params["password"]

# Modify params to show all user attributes
params["display"] = User.attributes.join(",")
user = User.find(user_id).include(User.goo_attrs_to_load(includes_param) + [:passwordHash]).first
authenticated = user.authenticate(user_password) unless user.nil?
error 401, "Username/password combination invalid" unless authenticated
user.show_apikey = true

if params["access_token"]
user = oauth_authenticate(params)
user.bring(*User.goo_attrs_to_load(includes_param))
else
user = login_password_authenticate(params)
end
user.show_apikey = true unless user.nil?
reply user
end

Expand All @@ -20,17 +23,13 @@ class UsersController < ApplicationController
post "/create_reset_password_token" do
email = params["email"]
username = params["username"]
user = LinkedData::Models::User.where(email: email, username: username).include(LinkedData::Models::User.attributes).first
error 404, "User not found" unless user
reset_token = token(36)
user.resetToken = reset_token
user = send_reset_token(email, username)

if user.valid?
user.save(override_security: true)
LinkedData::Utils::Notifications.reset_password(user, reset_token)
halt 204
else
error 422, user.errors
end
halt 204
end

##
Expand All @@ -42,11 +41,11 @@ class UsersController < ApplicationController
email = params["email"] || ""
username = params["username"] || ""
token = params["token"] || ""

params["display"] = User.attributes.join(",") # used to serialize everything via the serializer
user = LinkedData::Models::User.where(email: email, username: username).include(User.goo_attrs_to_load(includes_param)).first
error 404, "User not found" unless user
if token.eql?(user.resetToken)
user.show_apikey = true

user, token_accepted = reset_password(email, username, token)
if token_accepted
reply user
else
error 403, "Password reset not authorized with this token"
Expand Down Expand Up @@ -98,27 +97,14 @@ class UsersController < ApplicationController

private

def token(len)
chars = ("a".."z").to_a + ("A".."Z").to_a + ("1".."9").to_a
token = ""
1.upto(len) { |i| token << chars[rand(chars.size-1)] }
token
end

def create_user
params ||= @params
user = User.find(params["username"]).first
error 409, "User with username `#{params["username"]}` already exists" unless user.nil?
user = instance_from_params(User, params)
if user.valid?
user.save
# Send an email to the administrator to warn him about the newly created user
begin
if !LinkedData.settings.admin_emails.nil? && !LinkedData.settings.admin_emails.empty?
LinkedData::Utils::Notifications.new_user(user)
end
rescue Exception => e
end
user.save(send_notifications: false)
else
error 422, user.errors
end
Expand Down
16 changes: 15 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,14 @@ services:

redis-ut:
image: redis
ports:
- 6379:6379

4store-ut:
image: bde2020/4store
#volume: fourstore:/var/lib/4store
ports:
- 9000:9000
command: >
bash -c "4s-backend-setup --segments 4 ontoportal_kb
&& 4s-backend ontoportal_kb
Expand All @@ -88,10 +92,20 @@ services:


solr-ut:
image: ontoportal/solr-ut:0.1
image: solr:8
volumes:
- ./test/solr/configsets:/configsets:ro
ports:
- "8983:8983"
command: >
bash -c "precreate-core term_search_core1 /configsets/term_search
&& precreate-core prop_search_core1 /configsets/property_search
&& solr-foreground"

mgrep-ut:
image: ontoportal/mgrep-ncbo:0.1
ports:
- "55556:55555"

agraph-ut:
image: franzinc/agraph:v7.3.0
Expand Down
1 change: 1 addition & 0 deletions helpers/search_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ def populate_classes_from_search(classes, ontology_acronyms=nil)
doc[:submission] = old_class.submission
doc[:properties] = MultiJson.load(doc.delete(:propertyRaw)) if include_param_contains?(:properties)
instance = LinkedData::Models::Class.read_only(doc)
instance.prefLabel = instance.prefLabel.first if instance.prefLabel.is_a?(Array)
classes_hash[ont_uri_class_uri] = instance
end

Expand Down
49 changes: 49 additions & 0 deletions helpers/users_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,55 @@ def filter_for_user_onts(obj)

obj
end

def send_reset_token(email, username)
user = LinkedData::Models::User.where(email: email, username: username).include(LinkedData::Models::User.attributes).first
error 404, "User not found" unless user
reset_token = token(36)
user.resetToken = reset_token

return user if user.valid?

user.save(override_security: true)
LinkedData::Utils::Notifications.reset_password(user, reset_token)
user
end

def token(len)
chars = ("a".."z").to_a + ("A".."Z").to_a + ("1".."9").to_a
token = ""
1.upto(len) { |i| token << chars[rand(chars.size-1)] }
token
end

def reset_password(email, username, token)
user = LinkedData::Models::User.where(email: email, username: username).include(User.goo_attrs_to_load(includes_param)).first

error 404, "User not found" unless user

user.show_apikey = true

[user, token.eql?(user.resetToken)]
end

def oauth_authenticate(params)
access_token = params["access_token"]
provider = params["token_provider"]
user = LinkedData::Models::User.oauth_authenticate(access_token, provider)
error 401, "Access token invalid"if user.nil?
user
end

def login_password_authenticate(params)
user_id = params["user"]
user_password = params["password"]
user = User.find(user_id).include(User.goo_attrs_to_load(includes_param) + [:passwordHash]).first
authenticated = false
authenticated = user.authenticate(user_password) unless user.nil?
error 401, "Username/password combination invalid" unless authenticated

user
end
end
end
end
Expand Down
Loading