Workshop sobre Play na Caelum

Oi pessoal, no próximo sábado vou dar um workshop de 8 horas sobre a versão Java do Play. O treinamento será ministrado na Caelum.

O objetivo é construir uma aplicação usando várias das features disponíveis no framework. Caso você esteja começando com o Play na sua empresa ou até já esteja usando a um tempo, mas ainda não tem aquela confiança em tudo que está acontecendo, essas 8 horas podem ser de grande ajuda.

Espero por vocês! 🙂

Login/Password authentication in Secure Social

In another post I wrote about how to configure secure social to log in using a
social network. In this one, I am gonna walk through another common scenario,
setup a login/password based authentication. You need to understand a few things to put
everything in order. Let’s go!

If you don’t know anything about secure social, click in the link above and
spend a few minutes to read the other post about how to setup secure social :).
The first thing you have to change is the provider used in the configuration file,
usually called securesocial.conf. You need to use the userpass
entry in order to configure some aspects of your authentication.

    userpass {
    	withUserNameSupport=false
    	sendWelcomeEmail=false
    	enableGravatarSupport=true
    	signupSkipLogin=true
    	tokenDuration=60
    	tokenDeleteInterval=5
    	minimumPasswordLength=8
    	enableTokenJob=true
    	hasher=bcrypt
    }

The most strange key, at least for me, is the first one. The withUserNameSupport tells to Secure Social to use the user name instead of the email as the login for the
application. Maybe the keys about tokens are not clear right now, but wait a little and everything will be solved.

Another part that must be changed is the plugin’s file. We need to change the provider
to use the UserPass provider instead of some social provider.

    1500:com.typesafe.plugin.CommonsMailerPlugin
    9994:securesocial.core.DefaultAuthenticatorStore
    9995:securesocial.core.DefaultIdGenerator
    9996:securesocial.core.providers.utils.DefaultPasswordValidator
    9997:securesocial.controllers.DefaultTemplatesPlugin
    9998:br.com.celerate.security.CelerateUserService
    9999:securesocial.core.providers.utils.BCryptPasswordHasher
    10001:securesocial.core.providers.UsernamePasswordProvider

We used the UsernamePasswordProvider class to handle the authentication
part for us and we had to configure other plugins which do other things. For example,
we need to hash the password(BCryptPasswordHasher), maybe send a email(CommonsMailerPlugin) and validate the password sent by the user(DefaultPasswordValidator). These plugins are not necessary when you are dealing with social authentication.

Maybe you have noticed that there is a plugin which is not from SecureSocial. It is
the CelerateUserService. You need to create a class to handle the process
of create a new user in the system, verify the existence of a user in your system, etc.
We created this same class in the other post, but now it will be a little bit different.

    public class CelerateUserService extends BaseUserService {

    	public CelerateUserService(Application application) {
    		super(application);
    		// TODO Auto-generated constructor stub
    	}

    	@Override
    	public Identity doSave(Identity user) {
    		final SystemUser systemUser = new SystemUser();
    		newSystemUser(user, systemUser);
    		Identity foundUser = doFind(user.identityId());
    		if (foundUser == null) {
    			return TransactionHelper.run(new Function0<WrapIdentity>() {

    				@Override
    				public WrapIdentity apply() throws Throwable {
    					JPA.em().persist(systemUser);
    					return new WrapIdentity(systemUser);
    				}
    			});
    		}
    		return foundUser;
    	}

    	private void newSystemUser(Identity user, final SystemUser systemUser) {
    		systemUser.setEmail(user.email().get());
    		systemUser.setLastName(user.lastName());
    		systemUser.setPassword(user.passwordInfo().get().password());
    		systemUser.setFirstName(user.firstName());
    		systemUser.setProvider(user.identityId().providerId());
    		PasswordInfo passwordInfo = user.passwordInfo().get();
    		String salt = passwordInfo.salt().isDefined() ? passwordInfo
    				.salt().get() : null;
    		systemUser.setPasswordInfo(new SystemPasswordInfo(passwordInfo
    				.hasher(), salt));
    	}

    	@Override
    	public void doSave(Token token) {
    		final SignupToken newToken = SignupToken.from(token);
    		TransactionHelper.run(new Runnable() {

    			@Override
    			public void run() {
    				JPA.em().persist(newToken);
    			}
    		});
    	}

    	@Override
    	public Identity doFind(final IdentityId identityId) {
    		return TransactionHelper.run(new Function0<WrapIdentity>() {

    			@Override
    			public WrapIdentity apply() throws Throwable {
    				Option<SystemUser> user = SystemUsers
    						.findByEmail(identityId.userId());
    				return user.isDefined() ? new WrapIdentity(user.get())
    						: null;
    			}
    		});
    	}

    	@Override
    	public Token doFindToken(final String tokenId) {
    		return TransactionHelper.run(new Function0<Token>() {

    			@Override
    			public Token apply() throws Throwable {
    				return JPA.em().find(SignupToken.class, tokenId)
    						.toSecureSocialToken();
    			}
    		});
    	}

    	@Override
    	public Identity doFindByEmailAndProvider(String email,
    			String providerId) {
    		return doFind(new IdentityId(email, providerId));
    	}

    	@Override
    	public void doDeleteToken(String uuid) {
    		// TODO Auto-generated method stub

    	}

    	@Override
    	public void doDeleteExpiredTokens() {
    		// TODO Auto-generated method stub

    	}

    }

There is a lot going on in this class. Let’s start with all methods that have
token as part of the name or receive a Token as a parameter. When you
want to save a new user, Secure Social uses a two step registration process.
First the new user need to register a email. After that Secure Social will send
an email with the generated token, that is why you need to use the Typesafe
mailer plugin. Here is an example of url:(exemplo aqui) When a user tries to
follow this url, Secure Social will try to validate this token and that is why
you need to override the methods doFindToken and doSave(Token token).
You have to find a way to store this information and query it later. I opted for
save the token in my database.

Other very important method is the doFindByEmailAndProvider(String email,String providerId) method. Every time a user tries to log in your application, this method will be invoked. Now you are probably asking to yourself: where is the password? You
don’t need to worry about. Instead of leave the responsibility of checking the
hashed password in your hands, Secure Social just asks for you to load a user
based on his email. With this user loaded(Identity interface), Secure Social will
use the method passwordInfo to compare the password passed as argument
with the password loaded from the database.

It is a little bit boring, I know, but we need to configure an extra file, the router.
There we need to put all actions that are needed to handle the login/password
based authentication.

    #secure social
    GET     /login                      securesocial.controllers.LoginPage.login
    GET     /logout                     securesocial.controllers.LoginPage.logout

    # User Registration and password handling
    GET     /signup                     securesocial.controllers.Registration.startSignUp
    POST    /signup                    securesocial.controllers.Registration.handleStartSignUp
    GET     /signup/:token              securesocial.controllers.Registration.signUp(token)
    POST    /signup/:token              securesocial.controllers.Registration.handleSignUp(token)

    GET     /authenticate/:provider     securesocial.controllers.ProviderController.authenticate(provider)
    POST    /authenticate/:provider     securesocial.controllers.ProviderController.authenticateByPost(provider)
    GET     /not-authorized             securesocial.controllers.ProviderController.notAuthorized

Notice that all routes are provided by Secure Social. For example, all signup process can be handle out of the box by the framework. Secure social comes with a few predefined templates that you  can start using as your login and signup views. Even if you do not want to use these templates,  you will still want to use all controllers to handle the process.

That is it! Now you can use this Secure Social to handle both social or login/password
authentication process. In another post, I will back showing how to customize the templates and how to override the defaut behavior of the controller. Thanks for reading!

 

Your Play project is Java and Scala, at the same time

In the moment of creation a Play application, we are obliged to choose between Java and Scala as the base of our code, which is good because you can prefer one or another. The problem with this choice is that the programmers, basically Java programmers, they think that is a final choice. It is not unusual see some doubts in Play’s user forum about how to do something in Java version which is already well know in Scala version. For example, how to implement Web Sockets.

Of course, if there is a Java way to accomplish the task, go ahead and use it but, if there is not a Java way or this way is worst than the Scala version, still go ahead and use Scala. This is the point of this post, Play is possibly the only framework thought to be used with Scala and Java together, and not separated. Another example, all view templates are written in Scala. You still have the router file :).

Let’s see some examples! The first one is if you need to receive a Option in your template. You can try to pass a Option from play.libs.F.Option to your template.

    @(maybeTag:JavaOption[Hashtag])

    @maybeTag.map { tag:Hashtag =>
          @tag
    }.getOrElse {
          tagless
    }

The problem is that template, that becomes a Scala class after compilation, does not have any conversion from play.libs.F.Option to scala.Option. So code showed above will not work. There is no problem at all, instead of pass Play’s wrapper as argument, you can create a new Scala Option and solve your problem.

    ok(views.html.index.render(scala.Option.apply(hashtag)));

Another situation. Sometimes you have a class that simply holds a value. For example, in one of my current projects, I have a class called ImportStat.

    public class ImportStat {

    	private Number count;
    	private PhotoStatus photoStatus;

    	public ImportStat(Number count, PhotoStatus photoStatus) {
    		super();
    		this.count = count;
    		this.photoStatus = photoStatus;
    	}

    	public Number getCount(){
    		return this.count;
    	}

    	public PhotoStatus photoStatus() {
    		return photoStatus;
    	}

    }

I need to print the count value to give some information about a task that is being done by some Actor in my system. One way to do this is:

    @for(stat <- stats) {
     	  @stat.photoStatus():@stat.getCount()
    }

But, with a minor change you can take advantage of Scala syntax sugar to return values of your objects. You can use the apply() method. So let’s change our class.

    public class ImportStat {

    	private Number count;
    	private PhotoStatus photoStatus;

    	public ImportStat(Number count, PhotoStatus photoStatus) {
    		super();
    		this.count = count;
    		this.photoStatus = photoStatus;
    	}

    	public Number apply(){
    		return this.count;
    	}

    	public PhotoStatus photoStatus() {
    		return photoStatus;
    	}

    }

Now, in your template, you can write something like this.

    @for(stat <- stats) {
     	  @stat.photoStatus():@stat()
    }

The last one is the better, at least for me. I needed to use SSE to push notifications to browser. I googled about it and found this link, there was not a Java version! So I kept looking for and I found this blog post, which showed to me that Scala version was already implemented and it is much better than Java way, even if you use the pull request that brings SSE to Java version. So, for this case, I preferred to write the controller in Scala. Let’s just take a look in how you can open a SSE connection.

    package controllers

    //imports

    object UpdatePhotosController extends Controller {

      val (chatOut, chatChannel) = Concurrent.broadcast[JsValue]

      def newPhotos() = Action {
        implicit req =>
          {
            Ok.feed(chatOut &> EventSource()).as("text/event-stream")
          }
      }
    }

Now, let’s look how you can push information through the channel. And we will make this from an Actor written in Java!

    public class UpdatePhotoPanelActor extends UntypedActor{

    	@Override
    	public void onReceive(Object message) throws Exception {
    		final String id = (String) message;
    		Photo photo;
    		try {
    			photo = JPA.withTransaction(new Function0() {

    				@Override
    				public Photo apply() throws Throwable {
    					return Photos.byId(id);
    				}
    			});
    		} catch (Throwable e) {
    			throw new Exception(e);
    		}

    		UpdatePhotosController.chatChannel()
    		    .push(PanelPhotosJson.toScalaJsValue(0,photo));
    	}

    }

That is it! Don’t be afraid to mix both languages. If you are in Java project, your code will be 90% in Java and just 10% in Scala, not a big problem. The important part of Play written in Scala is the core, to build real world application is not important which one you gonna pick :). Choose the option that better fits to your team.

Evitando Null Pointer Exception em Scala

No meu post anterior foi discutido uma maneira de tentar evitar os famigerados NPE nas aplicações escritas em Java. Atualmente, uma linguagem que tenho gostado bastante é Scala. Uma das idéias da linguagem é a de fornecer soluções prontas para problemas comuns que encontramos quando fazemos código em Java. Um exemplo muito bom disso é a idéia para evitar os NPEs.

Para exemplificar, será usada a mesma agenda que foi escrita no post anterior. Abaixo segue o código da agenda escrito em Scala:

 import scala.collection.mutable.Map
 class Agenda {
   private val contatos = Map[String,Contato]()
  //aqui adicionamos um contato no mapa usando o email como chave
   def adiciona (contato:Contato) {
        contatos += contato.email -> contato
   }
   def  buscaPor(email:String) = {
         if(contatos.contains(email)){
            contatos.get(email).get
         }
         else{
            null
         }
    }
 }

Aqui está sendo retornado o mesmo null que era retornado no post anterior. Vale salientar que dei uma forçada no código para deixar ele parecido com o escrito em Java. E o cliente segue abaixo:

 object TesteAgenda {
      def main(args : Array[String]) : Unit = {
             val agenda = new Agenda
  	     agenda.adiciona Contato("alberto","teste@teste.com.br")
 	     val contato = agenda buscaPor "teste2@teste.com.br"
             if(contato==null){
                  println("Nao foi achado")
             }
             else{
                  println(contato.nome)
             }
      }
 }

Para tentar evitar esse tipo de retorno, a linguagem já vem com uma implementação mais esperta do que a sugerida pelo Null Value Object e muito mais elegante do que a exibida no post anterior. A implementação está abaixo:

 def buscaPor(email:String):Option[Contato] = {
    if(contatos.contains(email)){
        Some(contatos.get(email).get)
    }
    else{
      None
    }
 }

Option é uma trait, que pode ser encarada como uma interface do Java, porém com mais poderes. Ela vem com duas implementações: Some(…), quando você quer indicar que algum objeto vai ser retornado e None para indicar que nada vai ser retornado. Agora no código cliente podemos usá-la da seguinte maneira:

  println(contato.getOrElse(Contato("nao encontrado", "email@email.com.br")).nome)

Dessa maneira é evitado o NPE a um custo bem pequeno. Sem a necessidade de herança ou implementações mais complexas, já está pronto :). E o método getOrElse faz o papel do if else que era feito antes.  O post de Tony Morris cita vários exemplos de uso dos métodos das Options, mostrando o que cada um faz por baixo do pano. O mais interessante é que a própria linguagem faz bastante uso de Options para resolver problemas.

O exemplo de buscar um valor no mapa é um caso típico de retornar uma Option, e o método get já foi implementado dessa forma.  Segue o código:

  def buscaPor(email:String) = contatos.get(email)

Pretendo continuar explorando a linguagem nos próximos posts do blog. Acredito que as possibilidades que ela nos traz durante o desenvolvimento do código valem bastante a pena.  Outros blogs a serem acompanhados, que vem escrevendo sobre Scala são os da Caelum e de Urubatan.