-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Elytron-security support for Database Identity Store #3654
Elytron-security support for Database Identity Store #3654
Conversation
@loicmathieu I started something (only the structure for now). |
You should also add documentation to the existing guide: docs/src/main/asciidoc/security-guide.adoc |
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-agroal-deployment</artifactId> | ||
</dependency> |
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.
Why is the agroal dependency needed ? Should the user application pull the quarkus-agroal
instead ?
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.
🤔 I used the flyway extension as inspiration source.... At this point, I don't know yet if elytron extension will need to manipulate the Agroal Datasource object (or if everything will be done at runtime).
You're right I should don't couple the 2 extensions).
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.
I hope so, at runtime :-), my understanding the other DB related extensions depend on Agroal
...oyment/src/main/java/io/quarkus/elytron/security/deployment/SecurityDeploymentProcessor.java
Outdated
Show resolved
Hide resolved
0ec6217
to
ca03d15
Compare
I continued the structure. I used Regarding the tests I will use Flyway to init a h2 instance to test the Jdbc realm (at some point I would like to test with hibernate generating a user table based an entity). |
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-agroal-deployment</artifactId> | ||
</dependency> |
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.
the dependency should be optional and you should document that for using this identity store a datasource is needed
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.
The deployment module has a dependency to the runtime module so this dependency should not be needed here
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.
Should it? I wouldn't mind it being opinionated.
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.
At the moment, I flagged optional.
IMHO, in real life there are more application using DBs as Identity Store rather than files.
From a developer point of view, he/she uses a DB for authentication, I'm almost sure, It will use hibernate/ flyway somewhere in the application. These dependencies actually includes Agroal but to make authentication work the dev will have to re-declare explicitly Agroal.
I understand the reason but the dependency organization looks a bit weird to me.
For me the 2 options are:
Include Agroal by default by the the security extension
Have a dedicated extension for JDBC realm, which makes sens since I had to import the dedicated wildfly-elytron-realm-jdbc.
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-agroal</artifactId> | ||
</dependency> |
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.
the dependency should be optional and you should document that for using this identity store a datasource is needed
...tron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/JdbcRealmConfig.java
Outdated
Show resolved
Hide resolved
...oyment/src/main/java/io/quarkus/elytron/security/deployment/SecurityDeploymentProcessor.java
Outdated
Show resolved
Hide resolved
@danielpetisme for retreiving the datasource, I would retrieve it from Arc. Why do you said it's not the correct way? As your builditem is at static init time Arc should be available. Or you should do the same that is done inside the flyway extension ... |
I'd expect it work as well. One thing that may have to be done is to add the Agroal producer similarly to the way it is done here but using a String option. |
@loicmathieu, thanks for the flyway reference :-), yea, except that I would not link it to Agroal in the code, but you are right, the optional dependency should be just enough to get that producer analyzed |
Thank you all for the quick review. @loic Arc is indeed present during the build time but it does found any implementation of Datasource. I didn't investigate further, I guess the Agroal DataSource should be available at during this step. |
ca03d15
to
ef9f581
Compare
I found the solution: Finally I didn't used Flyway to init the database, h2 automatically loads automatically SQL resources which permits to create the basic users. The tests are ✅ for a basic version,.
Note: Documentation and quickstarts are of course mandatory elements 😃 |
Elytron security is used by all other security extension. So if you add the agroal extension as a mandatory extension a rest service that uses oauth and mongo will pull the agroal extension (that may need a driver! Not checked). |
BuildProducer<SecurityRealmBuildItem> securityRealm, | ||
BuildProducer<PasswordRealmBuildItem> passwordRealm, | ||
BeanContainerBuildItem beanContainer, | ||
DataSourceInitializedBuildItem dataSourceInitialized) throws Exception { |
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.
Hi, I'm not sure the agroal code has to be referenced in. What about the idea discussed earlier where you have DataSource
produced by Agroal injected ? Only the integration tests module should include a non-optional agroal dependency, this module should not have any agroal dependency (or only in the test scope if the tests will be collocated), unless I'm missing something :-)
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.
🤔 Looking at the Flyway extension which relies use a CDI injection to get the Datasource instance, the deployment
module as a dependency on DataSourceInitializedBuildItem dataSourceInitialized
.
https://github.com/quarkusio/quarkus/blob/master/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/FlywayProcessor.java
My comprehension is this build item ensures you have an instance of a DataSource
before invoking the Producer
I'm not sure to understand how you want to get rid off the agroal-deployment
dependency...
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.
@danielpetisme If I understand it correctly, in order to be able to access an instance of DataSource
inside the SecurityRecorder
you must add the DataSourceInitializedBuildItem dataSourceInitialized
or there will not be any datasource yet in the bean factory.
So this is a build order issue ... and I'm afraid I don't know if there is a way to give a hint to the current build algorithm to execute this step after an other one.
If nobody find better solutions, I found three that all have some caveats:
- Separate this in a new extension to be able to have a hard dependency to Agroal
- Provide the DataSource lazily (with some kind of provider or proxy): maybe difficult to build
- Move the
DataSourceInitializedBuildItem
toquarkus-core-deployment
: the simplest one :)
Maybe you can use the third one for the moment to be able to easily finish your first implementation and discuss this point later on ?
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.
Oh, sorry, I missed that this is how the flyway processor does it. So please continue as you agreed with Loic.
My current concern is that this security module is not only about the DB, while Flyway is, so I was hoping that simply adding the agroal dependency to the user application only which needs a DB security storage would do, but I do not know now how else to enforce that the agroal is initialized first :-), let me actually ask, I think it can be of general interest. Some work around io.quarkus.deployment.Capabilities
might need to be done. But in meantime, please continue as you plan, thanks
Update I think the way to do it may be to check Capabilities, see section 2.3.1. So one would check if the Agroal capability is available, and if yes, then use Arc somehow to fetch the DataSource
produced by Agroal. This option can be reviewed later though...
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.
I propose to stick with the Agroal dependency set in the elytron-security
extension to move on.
IMHO, a dedicated elytron-security-jdbc
extension would be the easiest and the more explicit. The dev wouldn't have to do any further configuration.
I propose to discuss this point on zulip?
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.
@danielpetisme yes, maybe some people will have different solution on Zulip :)
Please include my three proposals on your message on Zulip as I don't go there very often.
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.
I noticed that I was wrong in my previous comment when I said the test are greens. It was loading the wrong Anyway, now I succeed to use the JdbcSecurityRealm to retrieve the user password. But when I do the evidence verification The |
9d70a0c
to
a24c3f7
Compare
I still have the I tried to create the I don't know what can I test ? Anyway, regarding the feature itself, Covering the scope of
I use (and abused?) the Configuration Map. A dev must provide 1 As discussed above, only proposing the "clear" password mapper was not acceptable, so I did the WDYT? |
@danielpetisme as I understand it, build dependency is based on procuding/consuming builditem, an extension that consumes a build item will be build after one that procudes it. But, as this one lies in the Maybe during the review of this PR someone will have a better idea but meanwhile this should works :) |
Since the majority of the discussion regarding the
|
@loicmathieu @sberyozkin genltemens, could you review the current code (focusing on the feature provided, the configuration properties and the tests), please. |
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.
Without more documentation of it I found hard to understand the configuration part that seems very complicated.
Maybe you should simplify the configuration to only what is necessary, even if wildfly propose more options.
Having to configure the index of the password and the group seems complex, maybe you can retrive them by name rather than index ?
What is the purpose of the attribute-mapping. ?
You should provides sensible default so a user can just use the extension with
quarkus.security.jdbc.enabled=true
Maybe with the query ... maybe not if you can create automatically the table ...
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.*; |
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 widlcard imports
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.
Either eclipse-formatter or the maven formatter plugin do this optimization
|
||
import io.quarkus.test.QuarkusUnitTest; | ||
|
||
public class CustomRoleDecoderTest extends JdbcSecurityRealmTest { |
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.
CustomRole is a cross-functionality of elytron-security, not sure it's useful to test it in with the jdbc auth mechanism as it should works for all mechanism.
import javax.ws.rs.PathParam; | ||
|
||
/** | ||
* @author Michal Szynkiewicz, [email protected] |
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.
Is this author tag comes from a wrong copy/paste ?
* Date: 6/13/18 | ||
*/ | ||
@Path("/parameterized-paths") | ||
public class ParametrizedPathsResource { |
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.
Why don't you reuse the existing io.quarkus.security.test.ParametrizedPathsResource
?
*/ | ||
@Path("/roles-class") | ||
@RolesAllowed("user") | ||
public class RolesEndpointClassLevel { |
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.
Why don't you reuse the existing io.quarkus.security.test.RolesEndpointClassLevel
?
* Date: 8/8/18 | ||
*/ | ||
@Path("subject") | ||
public class SubjectExposingResource { |
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.
Why don't you reuse the existing io.quarkus.security.test.SubjectExposingResource
?
|
||
@ApplicationScoped | ||
@ApplicationPath("/jaxrs-secured") | ||
public class TestApplication extends Application { |
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.
Why don't you reuse the existing io.quarkus.security.test.TestApplication
?
|
||
QueryBuilder queryBuilder = builder.principalQuery(principalQuery.sql).from(dataSource); | ||
|
||
AttributeMapper[] mappers = principalQuery.attributeMappings.entrySet() |
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.
This seems over complicated. The only attribute that we need is the group one no?
Or do we enable a developer to load additional user information in the table and add them as attributes ?
@loicmathieu providing defaults values for the principal query is tricky... Elytron jdbc configuration is not very sexy... the configuration I propose is a 1-1 mapping
would be mapped to
And since Elytron permits to define multiple queries, I provide the same feature. The options I see to ease the config could be to hardcode some attribute index and names (like is made for "groups") but IMO it's would require more documentation. The other one would be to provide a intermediate layer the dev could override (define a I'm open to discussion for this point |
Regarding the test, I think having a test case that can be run against the multiple provider is interesting so consider the jdbc test as a proposal of test refactoring. Currently a user can have multiple roles even if in the servlet/jaxrs is not used (mon role) + users are not event used. |
@danielpetisme still thinking that the configuration is complex, it's not an issue to not cover all the capabilities of an underlying library when building an extension. In fact, the extension uses a library to ease its implementation, that's all, maybe some day we will switch to something else that elytron and when it happens having too much configuration options could complexify this migration. For example, multiple principal queries didn't seems necessary to me at this point, even spring secyrity didn't support it ! |
I do understand.
WDYT? and if the dev don't want the default behavior, he/she explicits via properties as explained above? |
@danielpetisme what you propose it OK for me. For the creation of the default tables, you can open a followup issue if you don't want to implement it now. Again, not worth it to support multiple queries now, so you should simplify the proposed configuration. |
@loicmathieu I have several concerns with the default properties Given the 2 table described above, I have to do multiple queries:
I could do in 1 query if the user has only 1 role:
IMHO, is not a realistic configuration but I can provide it by default. Quickly, dev will need to do a one-to-many join (to load many roles) and this require an additional query (Is not clean to do Another point, regarding password. IMHO, Bcrypt is the norm, but the JDBC Security Realm password mappers are looking for columns index, so I can provide any default salt or iteration_count 😢 that means the password-mapper config is made by the
Note: Just to compare, with Spring the password mapping is a Bean ( Trust me, just as you I want to simplifies dev's life with a cool DX but the Maybe I spent to much time on it and can't see the balance between simplicity and efficiency... At the moment I would prefer to release something and see how it's adopted. Then based on facts we could simplify the config. WDYT? |
@danielpetisme if the But if you think that you made all that you think is feasible so let's stop here ;) Maybe others will have some ideas to simplify it. |
@danielpetisme sorry for a delay, I was actually under impression you'd go with enhancing |
@sberyozkin Sorry I don't understand. I didn't created any @loicmathieu I think indeed an abstraction layer would bring some Panache 😄 but I do agree I should stop here the current PR:
Other persons/PRs should cover the defaults values/abstraction layer. |
@danielpetisme you referred to |
Hi, I haven't read the code but as far as dependencies/extensions are concerned, I would avoid using optional dependencies because it's confusing for the user: he adds an extension and then has to figure out which optional dependencies he might need to get the feature working. I think I would largely prefer if we had separate extensions for the various security realms if they rely on various dependencies to provide very specific feature e.g. have a JDBC realm extension for JDBC, a Panache extension if we want to support Panache at some point. OK, it's a bit more verbose and requires to create new extensions but at least it's very clear for the users and just adding the extension makes it work properly. |
@gsmet request makes sense to me. Plus, it solves without the dependency issue without refactoring the current external extensions. |
Up? Ok for everyone I can create a dedicated extension? |
Hi @danielpetisme, @gsmet,
thanks |
Or do you mean that the users would have to add the Thanks, Sergey |
A |
Hi @danielpetisme, as far as I'm concerned, I'll support either the original option or the |
Hi @danielpetisme how are you, I CC-ed to you on Zulip, the users are asking, so the DB store support would be welcome and quite timely :-). Let us know please how it goes. |
Awesome if someone else feel the need. Regarding the refactoring per-se, I'll try to propose something before the end of this week (struggling with time). Regarding, |
@danielpetisme sounds good, thanks |
c7a354f
to
580e51d
Compare
As discussed I made a dedicate
To workaround . the problem, I remove the build item and I've added an explicit Arc init So far the tests fail but I think it's just a matter of time before spotting the problem. |
@danielpetisme thanks a lot; FYI, I think in some cases Arc is used directly depending on how early the bean is required. |
If I explicitly ask for a If I don't ask for it, I got an NPE when invoking I don't have a clue of what is the best option |
@mkouba, @gsmet Hi Martin, Guillaume, can you please advise @danielpetisme how to address it ? |
This needs to be formatted. The runtime module also needs to depend on quarkus-elytron-security (and the moment this dependency is only in the deployment module). Not having this dep will cause all kinds of problems. |
I have taken this PR and have attempted to get everything passing at #4273 |
@stuartwdouglas since you took control of the PR, should we close this one? |
The main issues were:
I need to spent a little bit more time going through it today, but on the whole it looks really good. I only took control because we have a very tight schedule to get security in for the 1.0 release so anything security related is likely going to be fast tracked. |
A proposal for #3586