Secure social login and Play authenticator together

It is quite common use facebook, twitter and other social networks as a login provider for application. In Play world, Secure Social is one of the most used! Here in the blog there is a tutorial that guides you to configure this extension in your project. But, it is also important that your web app provides a formal way to register new users, using a common registration form.

For this last case, the normal way to control user access is using the Play plugin, provided by the framework “out of the box”. The problem here is the integration between these two plugins. When your user authenticates through a social network, Secure Social is the one responsible for checking the access control, it already has annotations for this case. While that when the user authenticates, for instance, through your database, you will probably want to use the plugin annotation provided by Play to control the user access.

In order to use both together, you have to change the Play’s session with information that came from the social login. The good news is that Secure Social has this exactly feature! You can create a listener that can be notified when new social login is done :). Let’s see the code.

    class SocialLoginEventListener(app: play.Application) extends EventListener {
      override def id: String = "my_event_listener"

      def onEvent(event: Event, request: RequestHeader, session: Session): Option[Session] = {
        event match {
          case e: LoginEvent => {
            val loggedUser = event.user.asInstanceOf[WrapIdentity].getUser()
            Some(session.+(("email",loggedUser.getEmail())))
          }

          case e:LogoutEvent => Option(Session.deserialize(Map[String,String]()))
          case _ => None
        }
      }
    }

You just have to change the session. I put the email information here because this is the key being used for my Play Authenticator, fell free to change and use what is better for you. Another point is that Secure Social provides only a Scala version of this feature. Remember, it is not a problem, your Play project is Java and Scala! You can combine both languages to take advantage of both worlds.

Now you have to configure Secure Social to use your listener. You have to add an entry in your play.plugins file.

  9994:securesocial.core.DefaultAuthenticatorStore
  9995:securesocial.core.DefaultIdGenerator
  9997:securesocial.controllers.DefaultTemplatesPlugin
  #my implementation of a service
  9998:security.SocialUserService
  10001:securesocial.core.providers.FacebookProvider
  10009:securesocial.core.providers.InstagramProvider
  #listener
  10006:security.SocialLoginEventListener

That is it, now you are able to use both login ways together without a problem! As last week I did not write,  I am gonna write twice in this one.

Using Play-S3 plugin to upload files to Amazon.

One of the most common task in applications around the world is the file upload. And, nowadays, instead of store these files in our server, is quite normal send them to Amazon S3. In this post let’s see how to use the Play-S3 plugin for a Play application using Java.

The first problem is that this plugin only has a Scala version. What are you gonna do? Are you going to implement everything again? It seems a little bit over… As we has already discussed in another post, your Play project is Java and Scala, together! Let’s mix both languages and take advantage of this plugin.

The first thing you have to do is to add the Play-s3 as a dependency in your build.sbt file.

    libraryDependencies ++= Seq(
      javaJdbc,
      cache,
      javaJpa,
      "org.hibernate" % "hibernate-entitymanager" % "3.6.9.Final",
       "mysql" % "mysql-connector-java" % "5.1.20",
       "org.mindrot" % "jbcrypt" % "0.3m",
       "ws.securesocial" %% "securesocial" % "2.1.3",
       "nl.rhinofly" %% "play-s3" % "3.3.5"
)

Now you have to configure your access and secret key in order to enable the upload of files to S3. This configuration, as usual, is placed in the *.conf file of your application.

  aws.accessKeyId="accessKeyHere"
  aws.secretKey="secretKeyHere"

Previously, you could get these keys from your root account in Amazon but, for security reasons, a few weeks ago they started to force you to follow a new process to configure your keys. You have to use the Identity and Access Management (IAM) and create your keys. They suggest that you create a pair of keys for each kind of user that your application has. The choice is yours 🙂

Now let’s take a look in the code necessary to upload a file.

    val result:Future[Unit] = bucket + BucketFile("pdfs/yourfile.pdf",
      "application/pdf",IOUtils.toByteArray(new FileInputStream(pdfFile)),Some(PUBLIC_READ))

There are a two important objects here. Bucket and the BucketFile. The first is needed to identify which folder(bucket) contains all your uploaded files from your current application. It is easy to create this object.

    private val bucket = S3("youpet")

Probably you will create one bucket per application.

The BucketFile is just a wrapper with all information needed about your file being uploaded. The last parameter is a little bit important. It is recommended to pass which roles this file has. Here we are saying that everyone can read(download). All this code can be encapsulated in a Scala class that can be used from your Java code :).

    object AmazonS3 {
      private val bucket = S3("youpet")

      def upload(folder: String, file: File,fileName:String): WaitingForS3 = {
        val timestampedName = FilenameUtils.getBaseName(fileName)+"_"+System.currentTimeMillis()+"."+FilenameUtils.getExtension(fileName)
        val s3Url = bucket.url(s"${folder}/${timestampedName}")

        val result:Future[Unit] = bucket + BucketFile(s"${folder}/${timestampedName}",
          extractMimeType(fileName),
          IOUtils.toByteArray(new FileInputStream(file)),Some(PUBLIC_READ))

        result.map { unit =>
          Logger.debug(s"Enviou o arquivo $s3Url")
        }.recover {
          case S3Exception(status, code, message, originalXml) => Logger.info("Error: " + message)
        }

        new WaitingForS3(s3Url,result)
      }
    }

This same code is available here. Feel free to copy and use in your projects :). Of course you could use all these Scala classes from your Java code directly but, in this case there are “functions as parameters” and “case classes” that are hard to translate to Java code. It is better isolate this code in a Adapter class and only expose a simple method to your Java side.

That is it! Upload your files to S3 and just have to deal with the links of your uploaded files :). It is easy to maintain and you gain, as a bonus, things like cache out of the box :).

Composable pages and the Cache feature

The Cache feature provided by Play, in both versions, is very well known. It is so important, that has its own page in the documentation. Just to give a quick description. Once you have put the @Cache annotation in your action, after the first request, the html generated will be stored and reused for the consecutive requests. The same thing applies to the Scala version.

The downside of this approach is that, almost every page in our application, has a relation with the current logged user. So, if you put the name of the user in the home page, like in GUJ(brazilian java forum), you just lost the opportunity to use the cache feature. You always have to remember, this cache is global. One approach could be create cache entries related with the current user, but this will imply an explosion of entries in the cache implementation.

In one of my posts, that was related with the Big Pipe idea presented in the talk given by Linkedin, it was demonstrated how you can compose your pages, loading each piece from a different request. Something like Page as a Service :). If you follow this approach you can gain another thing, the ability to cache just certain pagelets from your page!

Let’s see how we could compose the home page of GUJ using the “big pipe” approach implemented by Linkedin.

    public static Result index() {
      F.Promise news = ServiceClientJ.makeServiceCall("recent/news");
      F.Promise recentTags = ServiceClientJ.makeServiceCall("recent/tags");
      F.Promise availableJobs = ServiceClientJ.makeServiceCall("jobs");
      F.Promise infoqNews = ServiceClientJ.makeServiceCall("infoqnews");

      F.Promise newsHtmlPromise = render(news, views.html.guj.news.f());
      F.Promise recentTagsHtmlPromise = render(recentTags, views.html.guj.recent_tags.f());
      F.Promise availableJobsHtmlPromise = render(availableJobs, views.html.guj.jobs.f());
      F.Promise infoqNewsHtmlPromise = render(infoqNews, views.html.guj.infoq_news.f());

      HtmlStream newsStream = Pagelet.renderStream(newsHtmlPromise, "news");
      HtmlStream recentTagsStream = Pagelet.renderStream(recentTagsHtmlPromise, "recentTags");
      HtmlStream availableJobsStream = Pagelet.renderStream(availableJobsHtmlPromise, "availableJobs");
      HtmlStream infoqNewsStream = Pagelet.renderStream(infoqNewsHtmlPromise, "infoqNews");

      HtmlStream body = HtmlStream.interleave(Arrays.asList(newsStream, recentTagsStream,availableJobsStream,infoqNewsStream));

      return ok(HtmlStream.toChunks(views.stream.guj.index.apply(body)));
    }

As you can see, the page is built based on several requests! If you, for example, want to cache the “recent tags” pagelet, just put the @Cache annotation in this controller’s action.

    public class RecentTags extends Controller{

    	@Cached(key = "recent_tags", duration = 3600)
    	public static Result index(){
    		return ok(views.html.tags.index.render(tags.top()));
    	}
    }

Now you are taking advantage of the cache feature! I really like this approach and I will try to use it in my next projects :).

Accessing url parameters as get parameters in Play

A few weeks ago, I published here a post explaining my approach to implement a multi tenant strategy in my application. My main problem was that I did not have access to the url parameters in order to extract the tenant id. Play does not provide any easy way to access this information. So I kept searching and I found one solution, not to pretty, but functional! Just to remember, here I have my action.

	public class TenantResourceAction extends Action{

		@Override
		public Promise call(Context ctx) throws Throwable {
			Long id = Long.parseLong(ctx.request().
					  getQueryString("clientId"));
			//do your stuff here
			return delegate.call(ctx);
		}

	}

The getQueryString(“clientd”) method does not return the value because, as explained here, Play’s team decided do not insert url parameters into the querystring parameters map. So I need to extract the client id from almost every url. For example, http://localhost:9000/user/3/photos. It’s mandatory to check if the current logged user owns the requested resource. To solve this issue was necessary to use some classes from Play core, what was nice to learn more about the tool that I use a lot :). The first part of the job was to extend GlobalSettings and override the Play’s default behavior.

	import play.GlobalSettings
	import play.api.{ GlobalSettings => ScalaGlobalSettings }
	import play.api.mvc.RequestHeader
	import play.api.mvc.Handler

	object Global extends GlobalSettings with ScalaGlobalSettings {

	  //overrided because it was generating a conflict
	  override def getControllerInstance[A](controllerClass: Class[A]) = controllerClass.newInstance();

	  override def onRequestReceived(request: RequestHeader): (RequestHeader, Handler) = {
	    val (rh, handler) = super.onRequestReceived(request)
	    val route = rh.tags("ROUTE_PATTERN")
		...
	  }

	}

Here I had too choose Scala because was necessary the usage of the tags method from Scala version of RequestHeader. This method contains some meta information created by Play during the processing of parsing a request. This is the case of ROUTE_PATTERN key. This key returns the configure value from your routes file that was used to handle the current request. Now that we have the route, for a given uri we have to be able to retrieve all dynamic and static part from this uri. This is the hardest part, because we have to deal with some hidden parts of Play :). When you download the source code of the project, you will see that there are a several projects. One of them is the Routes-Compiler, which is responsible for create the object that represents a parsed route. The class of this object is play.router.PathPattern.  Take a look at the code needed to build this object.

	package play.router

	import play.router.RoutesCompiler._

	object RoutesCompilerHack {

		lazy val parser = new RouteFileParser

		def transform(verb:String,path:String):PathPattern =
				parser.parse(s"$verb $path  fakepackage.fakecontroller.fakemethod")
				.get.head.asInstanceOf[Route].path
	}

In order to have this code working, I had to put it in a package called play.router. The RouteFileParser is a private package class and can’t be accessed outside. Essentially, it is hack :(. After that, is necessary to convert the current PathPattern object to a play.core.PathPattern, which has a method that receives a uri and returns the bound parts with their respective values.

	import play.router.RoutesCompilerHack
	import play.core.{ PathPattern => PlayCorePathPattern }
	import play.router.PathPart
	import play.router.DynamicPart
	import play.router.StaticPart
	import play.core.{DynamicPart => CoreDynamicPart}
	import play.core.{StaticPart => CoreStaticPart}

	object TentantIdExtractor {

	  def apply(confRoute:String,uri:String):String = {
            //here could be used some cache 🙂
	    val pathPattern:play.router.PathPattern	 = RoutesCompilerHack.transform("GET", confRoute)

		//Dynamic and Static objects used inside the Router compiler project
	    val routerCompilerParts = pathPattern.parts

		//Transforming them to play.core.Part(Dynamic and Static)
	    val coreParts = routerCompilerParts.map { part =>
	      part match {
	        case DynamicPart(name, constraint, _) => CoreDynamicPart(name,constraint,true)
	        case StaticPart(name) => {
	          //the first slash("/") was not being generated
	          if(name.startsWith("/")) CoreStaticPart(name) else CoreStaticPart(s"/$name")
	        }
	      }
	    }

		//build the play.core.PathPattern
	    val corePathPattern = PlayCorePathPattern(coreParts)

The objects DynamicPart and StaticPart are used internally in Play to represent the url parts. Now, that we built the play.core.PathPattern object, it is possible to query this object with a requested uri and to retrieve a Option object with the values.

     val result:Option[Map[String,Either[Throwable,String]]] = corePathPattern(uri)

This monster object, that could be encapsulated in some class, has all the dynamic values passed by client. Now we can search for some variable and get the value!

	result.get("clientId") match {
	    case Right(value) => value
	    case Left(e) => throw e
	}

To finish our job, we now can get this value and push into query parameters!

	override def onRequestReceived(request: RequestHeader): (RequestHeader, Handler) = {
	  val (rh, handler) = super.onRequestReceived(request)
	  val route = rh.tags("ROUTE_PATTERN")
	  val tenantId = TentantIdExtractor(route,request.uri)
	  val newParams = rh.queryString.+("clientId" -> List(tenantId))

	  val newRequestHeader = rh.copy(rh.id,rh.tags,rh.uri,rh.path,rh.method,rh.version,newParams,rh.headers,rh.remoteAddress)
	 (newRequestHeader, handler)
	}

We pushed the id and rebuilt the RequestHeader to make this new parameter available to be accessed through request.getQueryString(“clientId”). The code is available here and you can use in your multi tenants projects! That is it folks. I hope this has helped you to understand a little bit more about Play internals and how important is to know the tool that you are using. And please, if there is an easier way, let me know. I enjoyed to hack the framework but I prefer an easier code 🙂