Play Framework WebSocket reject connection with custom error code - scala

def socket: WebSocket = {
WebSocket.acceptOrResult[Message, Message] { implicit request: RequestHeader =>
serviceUserIdentity.getUserIdentity(request) map {
case Some(userIdentityPlay) if userIdentityPlay.hasValidLicense =>
Right(
ActorFlow.actorRef(out =>
ActorWSServer.props(out)
)
)
case Some(_) =>
Left(Results(4403)) //invalid user
case None =>
Left(Results(4401)) //session expired
} recover {
case exception: Exception =>
Left(InternalServerError)
}
}
}
This CloseEvent is what I get back from the server when the user doesn't have a valid license or he's session is expired.
CloseEvent {isTrusted: true, wasClean: false, code: 1006, reason: "", type: "close", …}
It looks like Result Http code (4403) is getting overwritten to 1006.
The result that I am expecting:
CloseEvent {isTrusted: true, wasClean: false, code: 4403, reason: "", type: "close", …}
Is there a way to achieve this at WebSocket.accept?
Or a workaround using play.api.http.websocket.CloseMessage?

Related

Is it harmful to throw in the subscribe onError Scala.RX an Observable<Closable>?

I am using an rx.lang.scala in a for-comprehension, which i want to fail fast. I also want the resource parameters to be closed if an exception occurs. Will the doOnTerminate execute properly if you throw the Exception / Throwable, as in the example provided below?
private def createAgreement(parameters: Params, output: ByteArrayOutputStream): Try[Unit] = Try {
output
.usedIn(AgreementCreator(parameters).createAgreement) //Observable.using(resource)(observableFactory, t => { dispose(t); IOUtils.closeQuietly(t) }, disposeEagerly)
.doOnTerminate(parameters.close()) //close resource
.toBlocking
.subscribe(_ => {},
e => throw e,
() => debug("completed"))
}

How do I handle a get reqest to an offline source in Angular2?

I have the following problem: I have a Angular 2 application which sends a get request like this:
getStatus(cb:(boolean, error) => void){
this.http.get(this.uri+'/forms/status')
.subscribe(
(res: Response) =>{
console.dir(res);
this.response = res;
if(res.status === 200)cb(true, null);
else cb(false, "No connection established");
}
)
}
So this method should check,if my service is online or not and should send a message to the user, if it is offline. My problem is that I always will get
Failed to load resource: net::ERR_CONNECTION_RESET
when I call the method.
My question is how I can handle it that the method just returns the boolean as false, when my service is offline.
Best regards.
Switching to
getStatus(cb:(boolean, error) => void){
this.http.get(this.uri+'/forms/status')
.map(val => true)
.catch(err => Observable.of([false])
.subscribe(
(res: boolean) => cb(res, res ? null : "No connection established");)
}
returns the error message:
ERROR in [default] C:\Development\Code\formcreator-ui\app\src\service\form.servi
ce.ts:66:8
Argument of type '(res: boolean) => void' is not assignable to parameter of type
'NextObserver<boolean[]> | ErrorObserver<boolean[]> | CompletionObserver<boolea
n[]> | ((value: boo...'.
Type '(res: boolean) => void' is not assignable to type '(value: boolean[]) =>
void'.
Types of parameters 'res' and 'value' are incompatible.
Type 'boolean[]' is not assignable to type 'boolean'.
If you mean to suppress the error message in the browser console, then you're out of luck. This error is created by the browser and there is no way avoiding it.
Otherwise this should do what you want.
getStatus(cb:(boolean, error) => void){
this.http.get(this.uri+'/forms/status')
.map(val => true)
.catch(err => Observable.of([false])
.subscribe(
(res: Response) => cb(res, res ? null : "No connection established");
)
}
but instead of cb I would do it like
getStatus(){
return this.http.get(this.uri+'/forms/status')
.map(val => true);
.catch(err => Observable.of([false])
}
then it can be used like
this.getStatus().subscribe(avail => avail ? doSomething() : console.log("No connection"));
Observables are to avoid callback hell, therefore using this feature is preferred instead of passing callbacks around.

Silhouette and mobile application

I've used as example play-silhouette-angular-seed.
Authorization via Satellizer works fine.
When I try to authorize via iOs app I got next error:
com.mohiva.play.silhouette.impl.exceptions.UnexpectedResponseException:
[Silhouette][facebook] Cannot build OAuth2Info because of invalid response format:
List((/access_token,List(ValidationError(List(error.path.missing),WrappedArray()))))
I got an error 400 in this function from OAuth2Provider.scala :
protected def getAccessToken(code: String)(implicit request: RequestHeader): Future[OAuth2Info] = {
httpLayer.url(settings.accessTokenURL).withHeaders(headers: _*).post(Map(
ClientID -> Seq(settings.clientID),
ClientSecret -> Seq(settings.clientSecret),
GrantType -> Seq(AuthorizationCode),
Code -> Seq(code),
RedirectURI -> Seq(resolveCallbackURL(settings.redirectURL))) ++ settings.accessTokenParams.mapValues(Seq(_))).flatMap { response =>
logger.debug("[Silhouette][%s] Access token response: [%s]".format(id, response.body))
Future.from(buildInfo(response))
}
}
This error has been risen because Satellizer for authentication via Facebook send to server an 'authentication code' and Silhouette server use this code to get Facebook 'access token' and create user.
Facebook iOs SDK, instead, obtained 'Access token' and I've tried to send it to server in Json in field 'code' like 'Satellizer.
To resolve this issue I send an 'access token' in Json field named 'access_token' and use next code to authenticate mobile application:
class MobileSocialAuthController #Inject() (
val messagesApi: MessagesApi,
userService: UserService,
authInfoRepository: AuthInfoRepository,
socialProviderRegistry: SocialProviderRegistry,
val env: Environment[User, JWTAuthenticator])
extends Silhouette[User, JWTAuthenticator]
{
def authenticate(provider: String) = UserAwareAction.async(parse.json) {
implicit request =>
provider match {
case "facebook" =>
request.body.asOpt[OAuth2Info] match {
case Some(authInfo) =>
(socialProviderRegistry.get[FacebookProvider](provider) match {
case Some(p: FacebookProvider) =>
for {
profile <-p.retrieveProfile(authInfo)
user <- userService.save(profile)
authInfo <- authInfoRepository.save(profile.loginInfo, authInfo)
authenticator <- env.authenticatorService.create(profile.loginInfo)
token <- env.authenticatorService.init(authenticator)
} yield {
env.eventBus.publish(LoginEvent(user, request, request2Messages))
Ok(Json.obj("token" -> token))
}
case _ => Future.failed(new ProviderException(s"Cannot authenticate with unexpected social provider $provider"))
}).recover {
case e: ProviderException =>
logger.error("Unexpected provider error", e)
Unauthorized(Json.obj("message" -> Messages("could.not.authenticate")))
}
case _ =>
Future(BadRequest(Json.obj(
"message" -> "Bad OAuth2 json.")))
}
case _ =>
Future(BadRequest(Json.obj(
"message" -> "You can use only Facebook account for authentication.")))
}
}
}
As a result, I have a token which I use in ios application to obtain resources.
This happens when the OAuth2Provider gets a response it can't parse, which is, any non-success response. So there can be many reasons for this error, for instance the authorization code is invalid or expired, or you haven't configured the redirect_uri properly (check your Facebook app configuration on the Facebook dev site to set the redirect_uri).
Silhouette does log the response it gets from Facebook which should help you debug what the actual issue is, the log line to look for is in the snippet you provided:
logger.debug("[Silhouette][%s] Access token response:...
So check your logs, there you should see the response from Facebook, likely with an error indicating why they couldn't give you an access_token.

control not entering in fold() method

i am trying to insert data from form to database but on form submission control does not enter in fold(error, success) method and runs the statement after it and redirects it to other page
this is my controller method
def submitinfo = Action { implicit request =>
signupForm.bindFromRequest().fold(
errors => BadRequest(views.html.signup(errors)),
data => {
println("************enter sucess case *********************")
signupcc.insertData(data.name, data.username, data.email, data.password)
})
println("************Redirecting to sucess page *********************")
Redirect(routes.Application.success)
}
here is my routes file
# Home page
GET / controllers.Application.index
GET /signup controllers.Application.signup
POST /submit controllers.Application.submitinfo
GET /success controllers.Application.success
GET /signin controllers.Application.signin
please tell me what i am doing wrong
Redirect action should be part of sucess case inside fold method:
def submitinfo = Action { implicit request =>
signupForm.bindFromRequest().fold(errors => BadRequest(views.html.signup(errors)),
data => {
println("************enter sucess case *********************")
signupcc.insertData(data.name, data.username, data.email, data.password)
println("************Redirecting to sucess page *********************")
Redirect(routes.Application.success)
})
}

Unable to run a POST action in play framework 2.2

I have a similar problem to this person and I am unsure why.
my post action is called from a form submission and the controller code
def processFreeDoc = UserAwareAction {
implicit request => {
userEmailForm.bindFromRequest.fold(
formWithErrors => {
Logger.error("Error processing the form %s "format formWithErrors.errors)
Redirect(routes.Application.index)
},
data => {
val sessionProduct = getSessionUnProcessedProduct(data.sessionId, data.documentName)
if(sessionProduct != null){
Logger.info("Found")
sessionProduct.updateProcessing(data.emailAddress, data.sessionId)
Redirect(routes.Application.index)
}
else
Logger.info("Nothing found")
Redirect(routes.Application.checkoutFree(data.sessionId))
}
)
}
}
is skipped entirely. There are no errors in the IDE(IDEA) console and the breakpoint at the entry of the method is not reached so none of the log messages are seen.
EDIT :
The relevant route in the routes file - POST /processFreeDoc controllers.Application.processFreeDoc