Skip to content

Comments

6364 oauth2 abstract#6365

Merged
kcondon merged 20 commits intoIQSS:developfrom
poikilotherm:6364-oauth2-abstract
Nov 25, 2019
Merged

6364 oauth2 abstract#6365
kcondon merged 20 commits intoIQSS:developfrom
poikilotherm:6364-oauth2-abstract

Conversation

@poikilotherm
Copy link
Contributor

@poikilotherm poikilotherm commented Nov 13, 2019

This has been tested live with GitHub provider on local cluster. As the underlying infrastructure has not changed since #5991 and #6155, it shouldn't be necessary to test all providers again (but as always: up to you).

One might argue that AbstractOAuth2AuthenticationProvider should be refactored into an interface, too. This is left for later, as @djbrooke and @pdurbin do like the smallest scope possible.

Please see also my comment below about what should be looked at for QA.

Related Issues

Pull Request Checklist

  • Unit tests completed
  • Merged latest from "develop" branch and resolved conflicts

@poikilotherm poikilotherm requested a review from pdurbin November 13, 2019 13:56
@poikilotherm
Copy link
Contributor Author

Looks like upgrading to JUnit 5.5 makes test cases unhappy. Investigating.

@coveralls
Copy link

coveralls commented Nov 13, 2019

Coverage Status

Coverage increased (+0.1%) to 19.564% when pulling 9a4b49f on poikilotherm:6364-oauth2-abstract into 3667976 on IQSS:develop.

@poikilotherm
Copy link
Contributor Author

Ok, fixed as of 9f594b9 : reseting the FacesContext after all test cases helps 😉

Copy link
Member

@pdurbin pdurbin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@poikilotherm as we've been discussing in IRC, this looks good but our plan is for you to add OIDC support, probably in a new branch. We can leave this one around as a smaller branch for code reviewers to look at.

@poikilotherm
Copy link
Contributor Author

I got pretty far with OIDC yesterday. Already have it linked in the UI, building the URl for redirect works, too. Next up is retrieving user info. PR forthcoming, probably creating another small issue from the epic #5974 like we did here.

@djbrooke
Copy link
Contributor

@poikilotherm we discussed this a bit after standup today. We're willing to move this forward as refactoring, but to help us with testing, can you provide some guidance about areas of the code that had heavy changes and areas that you see as particularly complex and that have more risk? Thank you!

@poikilotherm
Copy link
Contributor Author

poikilotherm commented Nov 21, 2019

@pdurbin asked me to add an update in a comment. Please see my notes in #6226 about this, too. 🤔

Based on what I changed, I suggest testing the following:

  • Only the OAuth2 authentication infrastructure has been touched. No Shib, no builtin changes. So only that part needs testing.

    • Up to this point, this has been tested with GitHub and Google provider on local cluster by me.
  • You should run the usual test suites for unit and API test to see if any test fail due to the JUnit 5.5 upgrade. (Unit tests already seem to fine according to Travis).

Futher comments:

  • I had test failures due to wrong locales, so I created a test for them, too. These are critical, but they are tested now 😎
  • All changes to OAuth2LoginBackingBean.java are unit tested now, as I added a unit test for the whole thing.
  • I introduced ClockUtil.java as a new helper to inject clock instances via CDI. Using java.time.Clock instead of relying on System.currentTimeMillis() for testing guarantees better time-critical unit tests.
    • IMHO all occurences of System.currentTimeMillis() should be refactored to use java.time.Clock (~20 places in the codebase remain).
    • If QA wants me to add TODOs to those, please give me a shout out.

@poikilotherm
Copy link
Contributor Author

Jesus, I just saw that unit test of mine fails now after pushing latest develop. Let me sort that out.

@poikilotherm poikilotherm self-assigned this Nov 21, 2019
@poikilotherm
Copy link
Contributor Author

Ok I cannot seem to fail this locally, but its flaky on Travis.
Looking at what fails, I see
grafik
which is an additional timeout.

This leads me to the impression that those pesky System.currentTimeMillis() for creating and verifying the state are causing trouble (which is well known for tests).

Consequence: be a good refactor, remove them and replace with proper java.time.Clock abstraction, so we can use a DeLorean for tests.

…tem.currentTimeMillis(). Using CDI injection of clock via ClockUtil.
…y due to clock resolution of >1msec when using createState() and parseStateFromRequest().
@poikilotherm
Copy link
Contributor Author

poikilotherm commented Nov 22, 2019

Ok test flakiness fixed since db1e8e7. Reran the CI job on Travis 4 times (before I broke the tests pretty fast on first try)

I'll add some notes to the testing scenarios above before sending to QA.

@pdurbin please do a quick code review of my last changes and then push to QA at will...

@poikilotherm poikilotherm assigned pdurbin and unassigned poikilotherm Nov 22, 2019
Copy link
Member

@pdurbin pdurbin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks good and the API test suite is passing according to https://jenkins.dataverse.org/job/IQSS-Dataverse-Develop-PR/job/PR-6365/9/

@pdurbin
Copy link
Member

pdurbin commented Nov 22, 2019

@kcondon please see the "Based on what I changed, I suggest testing the following" note from @poikilotherm at #6365 (comment)

@pdurbin pdurbin removed their assignment Nov 22, 2019
@djbrooke
Copy link
Contributor

Thanks @poikilotherm for adding the additional details!

@kcondon kcondon self-assigned this Nov 22, 2019
@kcondon
Copy link
Contributor

kcondon commented Nov 22, 2019

@poikilotherm I'm getting an exception in the UI and log when I attempt log in with Google. This works on develop. Here is the stack trace:

[2019-11-22T15:57:25.126-0500] [glassfish 4.1] [WARNING] [] [javax.enterprise.resource.webcontainer.jsf.lifecycle] [tid: _ThreadID=54 ThreadName=jk-connector(2)] [timeMillis: 1574456245126] [levelValue: 900] [[
#{OAuth2Page.exchangeCodeForToken()}: com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse: {
"error": "invalid_request",
"error_description": "Missing parameter: redirect_uri"
}
javax.faces.FacesException: #{OAuth2Page.exchangeCodeForToken()}: com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse: {
"error": "invalid_request",
"error_description": "Missing parameter: redirect_uri"
}
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:118)
at javax.faces.component.UIViewAction.broadcast(UIViewAction.java:562)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:344)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.glassfish.tyrus.servlet.TyrusServletFilter.doFilter(TyrusServletFilter.java:295)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.ocpsoft.rewrite.servlet.RewriteFilter.doFilter(RewriteFilter.java:226)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:316)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:412)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:282)
at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:201)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:175)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:561)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:565)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:545)
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.faces.el.EvaluationException: com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse: {
"error": "invalid_request",
"error_description": "Missing parameter: redirect_uri"
}
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:101)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
... 45 more
Caused by: com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse: {
"error": "invalid_request",
"error_description": "Missing parameter: redirect_uri"
}
at com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor.generateError(OAuth2AccessTokenJsonExtractor.java:72)
at com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor.extract(OAuth2AccessTokenJsonExtractor.java:40)
at com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor.extract(OAuth2AccessTokenJsonExtractor.java:18)
at com.github.scribejava.core.oauth.OAuth20Service.sendAccessTokenRequestSync(OAuth20Service.java:53)
at com.github.scribejava.core.oauth.OAuth20Service.getAccessToken(OAuth20Service.java:97)
at com.github.scribejava.core.oauth.OAuth20Service.getAccessToken(OAuth20Service.java:92)
at edu.harvard.iq.dataverse.authorization.providers.oauth2.AbstractOAuth2AuthenticationProvider.getUserRecord(AbstractOAuth2AuthenticationProvider.java:157)
at edu.harvard.iq.dataverse.authorization.providers.oauth2.OAuth2LoginBackingBean.exchangeCodeForToken(OAuth2LoginBackingBean.java:97)
at edu.harvard.iq.dataverse.authorization.providers.oauth2.OAuth2LoginBackingBean$Proxy$
$$_WeldSubclass.exchangeCodeForToken(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at javax.el.ELUtil.invokeMethod(ELUtil.java:332)
at javax.el.BeanELResolver.invoke(BeanELResolver.java:537)
at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:256)
at com.sun.el.parser.AstValue.invoke(AstValue.java:283)
at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304)
at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87)
... 46 more
]]

@kcondon kcondon assigned poikilotherm and unassigned kcondon Nov 22, 2019
@poikilotherm
Copy link
Contributor Author

poikilotherm commented Nov 25, 2019

Ok @kcondon fixed as of 9a4b49f.
I tested this works now with GitHub, ORCID Sandbox and Google providers on my local test cluster.

Background: following https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type#exchange-the-authorization-code-for-an-access-token, some providers (like Google) require the redirect_uri parameter also when requesting the access token (despite it wouldn't be necessary).

@poikilotherm poikilotherm assigned kcondon and unassigned poikilotherm Nov 25, 2019
@pdurbin
Copy link
Member

pdurbin commented Nov 25, 2019

@poikilotherm thanks for fixing that bug. Your commit makes sense.

Thanks also for giving us a preview of the next pull request where you're adding the OIDC feature! This "diff" is looking good! poikilotherm/dataverse@6364-oauth2-abstract...poikilotherm:5974-oidc-impl

@kcondon
Copy link
Contributor

kcondon commented Nov 25, 2019

@poikilotherm Thanks for the fix and the explanation.

@kcondon kcondon merged commit 9df23c3 into IQSS:develop Nov 25, 2019
@djbrooke djbrooke added this to the 4.19 milestone Nov 25, 2019
@poikilotherm poikilotherm deleted the 6364-oauth2-abstract branch November 26, 2019 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor OAuth2 login to avoid hard dependencies on ScribeJava

5 participants