nulab / scala-oauth2-provider Goto Github PK
View Code? Open in Web Editor NEWOAuth 2.0 server-side implementation written in Scala
License: MIT License
OAuth 2.0 server-side implementation written in Scala
License: MIT License
OAuth2Provider API in play2-oauth2-provider returns PlainResult.
https://github.com/nulab/scala-oauth2-provider/blob/0.3.0/play2-oauth2-provider/src/main/scala/scalaoauth2/provider/OAuth2Provider.scala
However, PlainResult already is deprecated type in Playframework 2.2.
It should be changed to SimpleResult.
When obtaining the access_token, do you support Authorization: Basic, instead of query param ?
Instead of:
http://localhost:9000/oauth2/access_token?grant_type=password&client_id=test_client_id&client_secret=test_client_secret&username=test_user&password=test_password
More secure
POST /oauth2/access_token HTTP/1.1
User-Agent: curl/7.30.0
Host: localhost:9000
Authorization: Basic eHZ6MWV2RlM0d0VFUFRHRUZQSEJvZzpMOHFxOVBaeVJn
NmllS0dFS2hab2xHQzB2SldMdzhpRUo4OERSZHlPZw==
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 29
Accept-Encoding: gzip
grant_type=client_credentials
Hello
I am using the play-2.2 branch and i could not found any implementation of the DataHandler that returns Futures.
I don't want to block my app so i will probably implement it my self. Should i send a pull request after i finish it?
Regards, Diego
Hi,
Where do i need to validate the scope requested (by the client) with scope allowed for that specific client ?
I have been playing with scala-oauth2-provider for a few days. Can you provide with a sample Play2 app that demonstrates how to use play2-oauth2-provider
?
Hi,
Thanks a lot for your great work. Is there a sample app for play 2.3 ? I really need this
Hello,
I'm currently using the 0.9.0 release.
"com.nulab-inc" %% "play2-oauth2-provider" % "0.9.0",
I need an user hierarchy in my project, but i cant use it in DataHandler trait because the AuthInfo[U] class is invariant.
Any specific reasons for the type U to not be covariant?
This is probably a strange request, but my 'user' depends on some information found from the client_id. It is the only method in DataHandler that doesn't have some access to that information (that produces a User).
Hi,
Thank you for the useful oauth2.0 implementation.
I found another example usage of this project:
https://github.com/tuxdna/play-oauth2-server
This example is more comprehensive, it will help other users.
Can I add it to the readme-->examples section?
Thanks,
Golan
With the recent launch of the final OpenID Connect 1.0 Specification, are there any plans to implement OpenID Connect on top of the OAuth2 provider in this library?
I can't figure out how i should implement my DataHandler to validate both Client and User.
In the sample provided in the Play 2.2 sample, we have both User and Client entities, but in the findClientUser method, None is returned.
def findClientUser(clientId: String, clientSecret: String, scope: Option[String]): Option[User] = {
None // Not implemented yet
}
The question is, how can i return a user, if i am trying to authenticate with a Client (client_credentials) ?
Thanks for this great library!
Any plans to provide a Java version?
You you know any Java wrapper implementation out there?
Hi 😄
Is there already any kind of support for WebSocket based actions?
I had made something like this to make it work here.
trait OAuth2AsyncProvider2 extends OAuth2AsyncProvider {
def authorized[A, U](dataHandler: DataHandler[U])(implicit request: RequestHeader): Future[Either[OAuthError, AuthInfo[U]]] =
ProtectedResource.handleRequest(request, dataHandler)
}
Controller:
def liveMatch = WebSocket.async[JsValue] {
implicit request =>
authorized(MyDataHandler).flatMap {
_ match {
case Right(authInfo) => GameStream join authInfo.user
case Left(error) =>
// Just consume and ignore the input
val in = Iteratee.foreach[JsValue](_ => {})
// Send the error message and close
val out = Enumerator[JsValue](
JsObject(Seq("error" -> JsString(error.description)))
).andThen(Enumerator.enumInput(Input.EOF))
Future.successful((in, out))
}
}
}
If there isn't, do you plan to support it or we should just use the ProtectedResource class?
ProtectedResource.handleRequest(request, dataHandler)
Currently thats what I get:
[warn] problem while downloading module descriptor: https://repo1.maven.org/maven2/com/nulab-inc/play2-oauth2-provider_2.11/0.15.0/play2-oauth2-provider_2.11-0.15.0.pom: invalid sha1: expected=a7f3dd2d7727011266328183c15e32af79f9c3d8 computed=01576f30fc55d27113d440651119d5392e2fab7a (404ms)
[warn] module not found: com.nulab-inc#play2-oauth2-provider_2.11;0.15.0
[warn] ==== local: tried
[warn] /Users/schmitch/.ivy2/local/com.nulab-inc/play2-oauth2-provider_2.11/0.15.0/ivys/ivy.xml
[warn] ==== public: tried
[warn] https://repo1.maven.org/maven2/com/nulab-inc/play2-oauth2-provider_2.11/0.15.0/play2-oauth2-provider_2.11-0.15.0.pom
Actually I got this after clearing my Ivy2 cache ;)
The README has a section on "Customizing Grant Handlers". It has some code that says to create a custom class MyTokenEndpoint which extends TokenEndpoint. Where would I put this code and how would I reference/use it?
Essentially I want to set "clientCredentialRequired = false"
Thanks, David
I am testing this provider, and noticed that certain required fields MUST be in the query string. This is very bad for things like username & password, instead they should be allowed to be in either the headers, or a request body. The latter is probably more work, but making it work for headers should be pretty simple. I think that this should work if placed in RequestBase.scala and used instead of "requireParam" methods:
def require(name: String): String =
(param(name), header(name)) match {
case (None, Some(header)) => header
case (Some(parameter), None) => parameter
case (_, _) => throw new InvalidRequest("required parameter: " + name)
}
Hi,
Looks like TokenEndpoint.handleRequest
throws empty InvalidClient()
exception when an invalid client is detected. It causes some HTTP servers (Spray in my case) to choke on the response:
[WARN] [06/28/2015 11:08:30.668] [Oauth2FuncInMemorySpec-akka.actor.default-dispatcher-6] [akka://Oauth2FuncInMemorySpec/user/IO-HTTP/group-0/0] Illegal response header: Illegal 'WWW-Authenticate' header: Unexpected end of input, expected OptWS, Token or QuotedString (line 1, pos 58):
Bearer realm=test,error=invalid_client,error_description=
^
Here is the whole response:
HttpResponse(401 Unauthorized,HttpEntity(application/json; charset=UTF-8,{"error":"invalid_client","error_description":""}),List(Server: spray-can/1.3.3, Date: Sun, 28 Jun 2015 15:08:30 GMT, WWW-Authenticate: Bearer realm=test,error=invalid_client,error_description=, Content-Type: application/json; charset=UTF-8, Content-Length: 49),HTTP/1.1)
Should it provide at least some minimalistic description like (lines 24-25 in
if (!validClient) {
Future.successful(Left(new InvalidClient("Invalid client is detected")))
Thanks,
Alex
I'm not sure why, but I noticed that the build for this project doesn't do cross compilation correctly, e.g. sbt +publish
only publishes the main version. I was doing:
sbt
> ++ 2.11.0
[info] Setting version to 2.11.0
> publish
...
in order to publish the 2.11 artifacts. Do you mind doing the same an publishing to the central repo? A bigger question is what's wrong with cross-compiling, but we can solve that in a separate ticket?
The project looks very promising. I think it is the best fit also for java-play2 (and the only fit). Would it be hard to give a small java-example? For those who don't know Scala it is hard to guess a right translation.
Hi - apologies if this is more my misunderstanding than a real issue!
I would like to implement a 2 stage oauth server (such as described in https://developers.google.com/accounts/docs/OAuth2WebServer)
My main question is is this an intended use case of this library? If yes, should it be achieved by two client calls with different grant_types? Would it be possible to provide a short cheat sheet on how to approach?
My thinking so far is:
First call - needs to generate a "code" that can be exchanged for a token. Must be able to take a redirect URL, so this must make set grant_type to AuthorizationCode
Second call - to get an access token, would then be ClientCredentials, as this takes the client secret?
http://tools.ietf.org/html/rfc6749#section-4.2
The implicit grant type is used to obtain access tokens (it does not support the issuance of refresh tokens)
The authorization server MUST NOT issue a refresh token.
ImplicitGrantHandler
should not call AuthorizationHandler#refreshAccessToken
I don't think the Implicit grant type is really completed yet per OAuth Spec. Currently, you are required to implement the "validateClient" method, which checks a client Id and client secret. However, per the spec: http://tools.ietf.org/html/rfc6749#section-1.3.2 this is not valid. Implicit flows do not validate client secrets as implicit flows are used for things that can't be kept secret - like a Single Page App.
There is mention that you can validate the client identity - or at least that the request would be valid - if the client Id matches up properly with the registered redirect_uri.
As I'm using play framework 2.3.2 with scala 2.10.4 I received following exception:
java.lang.NoClassDefFoundError: play/api/mvc/SimpleResult
at controllers.MyController.<init>(MyController.scala:15) ~[na:na]
at Global$.controllersCache$lzycompute(Global.scala:92) ~[na:na]
at Global$.controllersCache(Global.scala:74) ~[na:na]
at Global$.getControllerInstance(Global.scala:98) ~[na:na]
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1$$anonfun$apply$15.apply(routes_routing.scala:133) ~[na:na]
Caused by: java.lang.ClassNotFoundException: play.api.mvc.SimpleResult
at java.net.URLClassLoader$1.run(URLClassLoader.java:366) ~[na:1.7.0_65]
at java.net.URLClassLoader$1.run(URLClassLoader.java:355) ~[na:1.7.0_65]
at java.security.AccessController.doPrivileged(Native Method) ~[na:1.7.0_65]
at java.net.URLClassLoader.findClass(URLClassLoader.java:354) ~[na:1.7.0_65]
at java.lang.ClassLoader.loadClass(ClassLoader.java:425) ~[na:1.7.0_65]
[error] application - Error while rendering default error page
scala.MatchError: java.lang.NoClassDefFoundError: play/api/mvc/SimpleResult (of class java.lang.NoClassDefFoundError)
at play.api.GlobalSettings$class.onError(GlobalSettings.scala:148) ~[play_2.10-2.3.2.jar:2.3.2]
at play.api.DefaultGlobal$.onError(GlobalSettings.scala:206) [play_2.10-2.3.2.jar:2.3.2]
at play.core.server.Server$class.logExceptionAndGetResult$1(Server.scala:76) [play_2.10-2.3.2.jar:2.3.2]
at play.core.server.Server$$anonfun$getHandlerFor$4.apply(Server.scala:86) [play_2.10-2.3.2.jar:2.3.2]
at play.core.server.Server$$anonfun$getHandlerFor$4.apply(Server.scala:84) [play_2.10-2.3.2.jar:2.3.2]
it happens due to deprecation added in play 2.3 of class SimpleResult which became just an alias. I have upgraded play version in your project (as it was hardcoded to 2.2 for scala 2.10) and everything works just fine.
I am probably misunderstanding something about the authorization code grant type but there is a findAuthInfoByCode in DataHandler, but no createAuthorizationCode. Can you explain why?
I expect that it has something to do with the fact that the code is generated after a successful login flow, which this library doesn't really have anything to do with, even though the library does verify that the authorization code corresponds to an authorized user/client when the client exchanges the authorization code for an access token. Is this correct?
Still, would it be a good idea to include a DataHandler.createAuthorizationCode just for symmetry's sake, to provide something for the login controller to hook into that fits into the rest of the oauth2 flow?
Is there already implicit grant type support or work around available? I can provide one if there is none already.
For not use casually Await.result in library.
Let users use it on their understanding.
does any setting do refresh token expires times.
After updating from .7 to .12 version on play 2.3 I'm having issue with type mismatch error. Here my simple code:
def confirm(waybillCode: String) = Action.async(parse.json) { implicit request =>
authorize(new OAuthDataHandler()) { authInfo =>
try {
request.body.validate[confirmJson].map { json =>
.... making simple calls to service layer ...
Ok(Json.obj("code" -> "200", "messages" -> s"Накладная ${waybillCode} доставлена ${json.name} ${json.position}"))
}.recoverTotal {
e: JsError => Future(Ok(JsError.toFlatJson(e)))
}
} catch{
case msg: Throwable => Future(InternalServerError(Json.obj("code" -> "500", "messages" -> msg.toString)))
}
}
}
I got the following error:
Error:Play 2 Compiler:
found : play.api.mvc.Result
required: scala.concurrent.Future[play.api.mvc.Result]
}.recoverTotal {
When I wrap Ok(JsError.toFlatJson(e)) with Future I get this one:
Error:(144, -1) Play 2 Compiler:
WaybillApi.scala:144: type mismatch;
found : Object
required: scala.concurrent.Future[play.api.mvc.Result]
Hi,
First of all thank you for this awesome library :)
Is there an example on how to use scala-oauth2-provider with spray or just without Play ?
Hi there,
Thanks for this awesome component. I'm having trouble implementing the Client credentials workflow, especially at the database level. On the majority of SQL schema I have seen, the client table doesn't contain a foreign_key to the user id. Thus, the method findClientUser in the DataHandler seems tricky to implement.
Have you any recommended SQL schema to use ?
Cheers,
Clément.
findUser(username, password)
arguments just use part of AuthorizationRequst parameters.
Instead, we can use findUser(request)
method that was implemented by Implit grant.
I have cloned the play2.4 example project https://github.com/tsuyoshizawa/scala-oauth2-provider-example-skinny-orm and created a custom token endpoint, but it does not compile. I am getting
the error object OAuthGrantType is not a member of package scalaoauth2.provider .
This happens when compiling the project in eclipse as well as from the shell with sbt compile.
The strange thing is that in an other project where I was using spray , I was able to implement
and successfully compile a custom endpoint.
So seems to be related somehow to play ?
Any suggestion ?
package controllers
import scalaoauth2.provider.TokenEndpoint
import scalaoauth2.provider.Password
import scalaoauth2.provider.OAuthGrantType._
class CustomTokenEndpoint extends TokenEndpoint {
val passwordNoCred = new Password() {
override def clientCredentialRequired = false
}
override val handlers = Map(
PASSWORD -> passwordNoCred)
}
Hi,
It seems that if you try to post JSON to the server it does not work. I am looking at this code. It would be useful to parse JSON body also:
final def getParam[A](request: Request[A]): Map[String, Seq[String]] = {
val form = request.body match {
case body: play.api.mvc.AnyContent if body.asFormUrlEncoded.isDefined => body.asFormUrlEncoded.get
case body: play.api.mvc.AnyContent if body.asMultipartFormData.isDefined => body.asMultipartFormData.get.asFormUrlEncoded
case body: Map[_, _] => body.asInstanceOf[Map[String, Seq[String]]]
case body: play.api.mvc.MultipartFormData[_] => body.asFormUrlEncoded
case _ => Map.empty[String, Seq[String]]
}
form ++ request.queryString.map {
case (k, v) => k -> (v ++ form.getOrElse(k, Nil))
}
}
Just for clarification purposes, under what circumstances is the 'clientId' field of AuthInfo 'None' rather than 'Some(string)'?
Please tell me how to implement refresh token
clientId
of AuthInfo
has wrapped Option
class by Make client credentials optional password #34 to not have empty string. I think this way is correct on Scala.
clientSecret
of ClientCredential
also might have empty string by ClientCredentialFetcher.
So I would like to change the clientSecret
of ClientCredential
to Option[String]
.
Hi,
I would like to implement OAuth2 provider using your library with a two-step sign in. (After providing initial username / password, user is requested to fill in code sent by email / SMS)
Is this something that's possible using your library or would I have to implement my own custom flow.
Thank you!
OAuth2Provider
imports scala.concurrent.ExecutionContext.Implicits.global
now.
However, Playframework provides play.api.libs.concurrent.Execution.Implicits.default
and support configuring the default thread pool.
So, OAuth2Provider
should be able to choose ExecutionContext
by adding implicit parameter.
I have a controller both have sync action and async action, that doesn't work well with scala-oauth2-provider
.
In order to use scala-oauth2-provider
, I have to break the actions into two controllers by its async/sync behaviour, not their business logic.
Is it possible to have a single trait with different methods like authorize
and authorizeAsync
? Or do you have any insight about this?
I have the 0.12.0 branch working with Play 2.3.4 & using Slick for persistance. All works well.
https://github.com/davidseth/scala-oauth2-provider-slick
Please add to your example section. Thanks.
First, thanks for developing and sharing this library. I'm building an OAuth2-protected REST API w/ Play/Scala and this saves me a ton of work.
The way you've implemented it though requires client credentials to always be used, even for the resource owner password credentials grant type for which they're optional per http://tools.ietf.org/html/rfc6749#section-4.3.2: "If the client type is confidential or the client was issued client credentials (or assigned other authentication requirements), the client MUST authenticate with the authorization server as described in Section 3.2.1."
I've looked at how to modify the code to make client credentials optional for this grant type but unfortunately don't see an obvious, clean way to do that as there are many places where this assumption is manifested (TokenEndpoint::handleRequest, Password::handleRequest, and AuthInfo class where clientId is String instead of Option[String]).
So the most expedient thing I can think of to avoid a lot of rework is changing ClientCredentialFetcher::fetch to return a special ClientCredential object with a special clientId representing "no credentials" . That way my DataHandler can check for that special value in validateClient.
Since I need this fixed soon I'll go ahead and make that change in my fork. Do you have any interest in either pulling that change from me or reworking your code to fix this issue more cleanly?
thx,
Chris
OAuth2Provider:: issueAccessToken() and OAuth2Provider::authorize() handle errors mostly the same except that issueAccessToken() includes a JSON body describing the error and authorize() doesn't. Is there a particular reason for not including the JSON body for authorize() errors? If not I'll submit a pull request with that fixed.
Hello,
I want authenticate user according to sub-domain. I am using Play-Framework 2.3, i just need to pass extra parameter with my domain in def validateClient(clientCredential: ClientCredential, grantType: String): Future[Boolean]
method, so, i will check user domain also. How can i, do that.
Hi,
When using scala-oauth2-provider, how can I do an integration with external identity providers?
Let's say, I have a mobile app where you can signup with an email/password or use a FB single-sign-on. The problem is with the second case, because, instead of providing an email/password we have an FB access token.
I don't see a way to by-pass the findUser(username: String, password: String): Option[U]
method from the DataHandler
.
Is there a way to have this working?
Otherwise, would it be acceptable to have DataHandler[U,C]
whith C
being the type of crendentials.
Thanks.
Nicolas
http://www.ietf.org/rfc/rfc2616.txt
4.2 Message Headers
HTTP header fields, which include general-header (section 4.5),
request-header (section 5.3), response-header (section 6.2), and
entity-header (section 7.1) fields, follow the same generic format as
that given in Section 3.1 of RFC 822 [9]. Each header field consists
of a name followed by a colon (":") and the field value. Field names
are case-insensitive.
Wasteful process is performed in access token generating.
I will add ClientCredential
to argument of GrantHandler#handleRequest
.
The parameter will be passed by TokenEndpoint#handleRequest
.
All grant handlers are now enable by default.
However, almost services don't use all grant.
All grants are enable is not good security. A service might unintentionally use some grant.
I want to change manually to enable grant to service.
Hi,
Firstly, great work on this lib; really helps a lot to have something like this to guide us in implementing a Scala Oauth2 provider :)
Cutting to the chase, it looks like this lib handles the generation of an AccessToken when provided an Authorisation Code. However, it doesn't seem to provide a way to ensure that once an AccessToken has been generated, the Authorisation code used gets destroyed, in order to ensure the following clause in section 4.1.2 of the RFC:
The client MUST NOT use the authorization code more than once. If an authorization code is used more than once, the authorization server MUST deny the request and SHOULD revoke (when possible) all tokens previously issued based on that authorization code. The authorization code is bound to the client identifier and redirection URI.
I think one way is to add a deleteAuthCode
method to AuthorizationHandler
, and have AuthorizationCode extends GrantHandler
call that upon successful completion of issueAccessToken
Any thoughts?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.