I am writing a single sign on plugin for SonarQube.
All my user information are located in the UserPrincipal of the HttpRequest (not the password ;-) ).
For the moment, I can sign on and provide the UserDetails to Sonar through the method
public UserDetails doGetUserDetails(Context context);
Now I would like to provide the groups of the user to SonarQube but the method
public Collection<String> doGetGroups(String username)
does not provide the context.
To solve my issue, I have modified the code of need_authentication.rb of Sonar (located in sonarqube-4.4\web\WEB-INF\lib)
to call a method
public Collection<String> doGetGroups(String username, HttpServletRequest)
I have written.
But I don't like modyfing source code; I would prefer overide it by extending the class PluginRealm of the file need_authentication.rb.
Basically, how do I extend a class in SonarQube ?
I know how to overide a controller but not class located in lib folder.
Also (I don't know Ruby at all).
Thank you for your help
SONAR-5430 will allow to natively implement such a feature.
For people who cannot use the solution of Fabrice, here is what I did until the new feature is released.
I create a controller in ruby I add to my plugin realm.
This controller extends ApplicationController controller.
It redefines authenticate method wich calls the default method of Sonar
def authenticate
begin
self.current_user = User.authenticate(nil, nil, servlet_request)
if self.current_user
my_synchronize_groups(servlet_request)
end
rescue Exception => e
self.current_user = nil
Rails.logger.error(e.message)
end
redirect_back_or_default(home_url)
end
When you use a User.authenticate(nil, nil, servlet_request) it calls the synchronize_groups(user) in need_authorization.rb and synchronize the groups.
What I do is calling my_synchronize_groups after User.authenticate(nil, nil, servlet_request) to override the groups synchronization done by sonar.
Here is the code of my_synchronize_groups
def my_synchronize_groups(servlet_request)
Rails.logger.debug("My synchronize_groups method")
myRealm = RealmFactory.realm
Rails.logger.debug("My realm #{myRealm}")
if myRealm
myGroupsProvider = myRealm.instance_variable_get(:#java_groups_provider)
Rails.logger.debug("My group provider #{myGroupsProvider}")
if myGroupsProvider
begin
groups = myGroupsProvider.doGetGroups(servlet_request)
rescue Exception => e
Rails.logger.error("Error from my groups provider: #{e.message}")
else
if groups
self.current_user.groups = []
for group_name in groups
group = Group.find_by_name(group_name)
if group
self.current_user.groups << group
end
end
end
end
end
end
end
The method myGroupsProvider.doGetGroups(servlet_request) is a method located in MyGroupsProvider.java which extends ExternalGroupsProvider.java and return a collection of String.
I am not saying it is the best solution but with my knowledge of Ruby ...
Hoping it can help
Simon
Related
Hey I have a graphql mutation which needs to be implemented before user logs in. Till now I have been using graphql endpoints only after User is fully authenticated. Since graphql controller inherits application controller which implements a before_action :authenticate_user! callback I always need a valid user inorder to use the graphql endpoints. Is there a way to configure certain graphql endpoint to not have a valid user.
How should I go about it?
You can add logic in execute method of GraphQlController that checks for exceptions.
For example, we want to skip authorization on "createSession" query that is supposed to generate JWT token for valid username/password combination. Trick is to create "Query" object where you can easily get to the query being invoked and determine if it's in skip list. Pardon the code it is first pass, just as proof of concept.
#class GraphqlController < Application Controller
#skips_authorization = ["createSession"]
def execute
variables = prepare_variables(params[:variables])
query = params[:query]
operation_name = params[:operationName]
current_user = AuthorizeApiRequest.call(request.headers).result
context = {
current_user: current_user,
}
query_parse = GraphQL::Query.new(ApiSchema, query_string = params[:query])
result = ApiSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
if current_user.present? || #skips_authorization.include?(query_parse.selected_operation.selections[0].name)
render json: result
else
render json: {}, status: 401
end
rescue StandardError => e
raise e unless Rails.env.development?
handle_error_in_development(e)
end
I prepared view in my PostgresDB called user_details. I created UserDetail entity and UserDetailRepository. Here you have shortened version of my view to visualize my problem:
CREATE VIEW user_details AS
SELECT id, user_name FROM users WHERE user_name like '$1#%'
My question is how to inject parameter using Hanami repository?
I can use raw sql in my repos which is described here http://hanamirb.org/guides/models/repositories/ but I prefer to create view in postgres using migrations. I don't want to improve query but to know if I can user parameterized queries with Hanami. Thanks for all answers
PostgreSQL doesn't support parameterized views in the way you described. It can have views that call a function which in order can access the current session state and you can set that state just before selecting data from the view. However, I'd recommend you define a method with an argument instead
class UserRepo
def user_details(prefix)
root.project { [id, user_name] }.where { user_name.ilike("#{ prefix }%") }.to_a
end
end
What you get with this is basically the same. If you want to use user_details as a base relation you can define a private method on the repo and call it from other public methods
class UserRepo
def user_details_filtered(user_name, min_user_id = 0)
user_details(prefix).where { id > min_user_id }.to_a
end
def user_details_created_after(user_name, after)
user_details(prefix).where { created_at > after }.to_a
end
private
# Don't call this method from the app code, this way
# you don't leak SQL-specific code into your domain
def user_details(prefix)
root.project { [id, user_name] }.where { user_name.ilike("#{ prefix }%") }
end
end
I have a user profile class and am checking if a user exists and if not want to create that user.
Am using the filter class for userprofile so that the client can call :
http://localhost:8000/users/?email=a#b.com
and if the result is empty will create a user with the email address.
Is there a way to intercept the query result and raise an exception when its empty and handle that to create the user.
If there is a better way would like to be corrected as well.
class UserQueryFilter(django_filters.rest_framework.FilterSet):
email = django_filters.CharFilter(name="user__email")
username = django_filters.CharFilter(name="user__username")
class Meta:
model = UserProfile
fields = ['email', 'username']
class UserViewSet(viewsets.ReadOnlyModelViewSet):
queryset = UserProfile.objects.all()
serializer_class = UserSerializer
filter_class = UserQueryFilter
Any help is appreciated.
Thanks
Anand
Django Rest Framework provide a functionality that is disabled by default. Maybe it could give you another approach to resolve your problem: PUT as create
In other hand, if you really need to create the user through a GET request with a querystring, you can use a MethodFilter from django-filters, for example:
class UserFilters(FilterSet):
user = MethodFilter(action='filter_user')
class Meta:
model = User
fields = ['user']
def filter_user(self, queryset, value):
if not value:
# Here Raise Exception
else:
# Check if the user exists, if not create it
users = queryset.filter(Q(username=value) | Q(email=value))
if not users.exists:
user = User.objects.create(...)
return queryset.filter(pk=user.id)
else:
return users
Hope this can help you. I'm not pretty sure about it works in that exact way but it's the idea.
Personally, I recommend you that try to execute that tasks through a more appropriate request like POST or PUT and manage in the corresponding method.
I have a User model that will return user studies that have a status of true:
has_many :user_studies, -> { where(status: true) }, dependent: :destroy
I am using this for over 80% of my functionality but there are some instances where I want to override this line of code.
I have a private method in the User controller that does the work of getting a user study:
def set_user_study
#user_study = #user.user_studies.find(params[:id])
end
#user is set in another private method:
def set_user
#user = users_api.find_by_guid(params[:user_id])
rescue Longboat::Api::Users::NotFound => e
logger.error e.message
raise ActionController::RoutingError.new('Not Found')
end
The private method is called when I try to edit a user_study(among others):
before_action :set_user_study, only: [:edit, :update, :destroy]
I am getting the following error(obviously) when trying to edit a study that does not have a status of true:
Couldn't find UserStudy with 'id'=1 [WHERE "user_studies"."user_id" = ? AND "user_studies"."status" = 't']
How can I continue to call the private method but allow a user to be able to edit a user study whether the status is true or not?
If your aim is to just override the association, don't use #user.user_studies . Instead, query out the values and use UserStudy.where(user_id: #user.id) in the private method. However, if the usage of user_studies is less in existing code, then just remove the condition in association and chain scopes to add this condition.
I am new to Ruby and came from C# world. In C# it is legal to do stuff like this:
public class Test
{
public void Method()
{
PrivateMethod();
}
private void PrivateMethod()
{
PrivateStaticMethod();
}
private static void PrivateStaticMethod()
{
}
}
Is it possible to do something similar in Ruby?
A little bit of context: I have a Rails app... One of the models has a private method that sets up some dependencies. There is a class method that creates initialized instance of the model. For legacy reasons there are some instances of the model that are not initialized correctly. I added an instance method that initializes 'uninitialized' instances where I want to do same initialization logic. Is there a way to avoid duplication?
Sample:
class MyModel < ActiveRecord::Base
def self.create_instance
model = MyModel.new
model.init_some_dependencies # this fails
model
end
def initialize_instance
// do some other work
other_init
// call private method
init_some_dependencies
end
private
def init_some_dependencies
end
end
I tried to convert my private method to a private class method, but I still get an error:
class MyModel < ActiveRecord::Base
def self.create_instance
model = MyModel.new
MyModel.init_some_dependencies_class(model)
model
end
def initialize_instance
# do some other work
other_init
# call private method
init_some_dependencies
end
private
def init_some_dependencies
MyModel.init_some_dependencies_class(self) # now this fails with exception
end
def self.init_some_dependencies_class(model)
# do something with model
end
private_class_method :init_some_dependencies_class
end
First let me try to explain why the code does not work
class MyModel < ActiveRecord::Base
def self.create_instance
model = MyModel.new
# in here, you are not inside of the instance scope, you are outside of the object
# so calling model.somemething can only access public method of the object.
model.init_some_dependencies
...
end
...
You could bypass private calling of the method with model.send :init_some_dependencies. But I think in this case there is probably better solution.
I would guess that init_some_dependencies probably contain more business / domain logic rather than persistence. That's why I would suggest to pull out this logic into a "Domain Object" (or some call it Service Object). Which is just a plain ruby object that contain domain logic.
This way you could separate persistence logic to ActiveRecord and the domain logic to that class. Hence you will not bloat the ActiveRecord Model. And you get the bonus of testing
the domain logic without the need of ActiveRecord. This will make your test faster.
You could create a file say `lib/MyModelDomain.rb'
class MyModelDomain
attr_accessor :my_model
def initialize(my_model)
#my_model = my_model
end
def init_some_dependencies
my_model.property = 'some value example'
end
end
Now you could use this object say something like this
class MyModel < ActiveRecord::Base
def self.create_instance
model = MyModel.new
domain = MyModelDomain.new(model)
domain.init_some_dependencies
domain.my_model
end
def initialize_instance
# do some other work
other_init
domain = MyModelDomain.new(self)
domain.init_some_dependencies
end
end
You might also want to move the initialize_instance if you think it's necessary
Some resource that go deep into this pattern:
http://railscasts.com/episodes/398-service-objects
https://www.destroyallsoftware.com/screencasts/catalog/extracting-domain-objects
You can use
model = MyModel.new
model.send :init_some_dependencies
to bypass method visibility checks.
In C# it is legal to do stuff like this:
public class Test
{
public void Method()
{
PrivateMethod();
}
private void PrivateMethod()
{
PrivateStaticMethod();
}
private static void PrivateStaticMethod()
{
}
}
Is it possible to do something similar in Ruby?
Yes:
class Test
def method
private_method()
end
def self.greet
puts 'Hi'
end
private_class_method :greet
private
def private_method
self.class.class_eval do
greet
end
end
end
Test.new.method
Test.greet
--output:--
Hi
1.rb:23:in `<main>': private method `greet' called for Test:Class (NoMethodError)
But ruby doesn't strictly enforce privacy. For instance,
class Dog
def initialize
#private = "secret password"
end
end
puts Dog.new.instance_variable_get(:#private)
--output:--
secret password
ruby gives you the freedom to access private things with a little bit of extra effort:
Test.new.method
Test.class_eval do
greet
end
--output:--
Hi
Hi
In ruby, a private method only means that you cannot explicitly specify a receiver for the method, i.e. there can't be a name and a dot to the left of the method. But in ruby, a method without a receiver implicitly uses self as the receiver. So to call a private method, you just have to create a context where self is the correct receiver. Both class_eval and instance_eval change self inside the block to their receiver, e.g.
some_obj.instance_eval do
#Inside here, self=some_obj
#Go crazy and call private methods defined in some_obj's class here
end
You can apply those rules to this situation:
(ahmy wrote:)
First let me try to explain why the code does not work
class MyModel < ActiveRecord::Base
def self.create_instance
model = MyModel.new
# in here, you are not inside of the instance scope, you are outside of the object
# so calling model.somemething can only access public method of the object.
model.init_some_dependencies # this fails
... end ...
"Context this" and "scope that"--what a headache. All you have to remember is: you cannot call a private method with an explicit receiver. The method init_some_dependencies was defined as a private method--yet it has "model." written to the left of it. That is an explicit receiver. Bang! An error.
Here is a solution:
class MyModel
def self.create_instance
#In here, self=MyModel
puts self
model = MyModel.new
model.instance_eval do #Changes self to model inside the block
#In here, self=model
init_some_dependencies #Implicitly uses self as the receiver, so that line is equivalent to model.init_some_dependencies
end
end
private
def init_some_dependencies
puts "Dependencies have been initialized!"
end
end
MyModel.create_instance
--output:--
MyModel
Dependencies have been initialized!
Or as ahmy and LBg pointed out, you can use Object#send() to call private methods:
class MyModel
def self.create_instance
model = MyModel.new
model.send(:init_some_dependencies, 10, 20)
end
private
def init_some_dependencies(*args)
puts "Dependencies have been initialized with: #{args}!"
end
end
MyModel.create_instance
--output:--
Dependencies have been initialized with: [10, 20]!
acturally, it surely does.
Ruby's some OO strategies(private & public keywords etc.) comes from C++, so you can get almost same usage.