Trabe ya no escribe aquí. Puedes encontrarnos en nuestra publicación en Medium: medium.com/trabe.

4Trabes Historias de una empresa en 100 metros cuadrados

El blog de Trabe Soluciones

Trabe busca programador

| | Comentarios

Buscamos a una persona que le guste programar. Necesitamos que sepa desarrollar software utilizando JEE o Ruby on Rails. No buscamos jefes de proyecto, analistas funcionales o arquitectos software. Lo que necesitamos es un buen programador.

Solemos desarrollar aplicaciones web desde cero, así que nuestro candidato perfecto tendría esta pinta:

  • Tiene experiencia desarrollando con Java. Domina Spring e Hibernate. Domina Spring MVC y ha trabajado con Struts. También conoce Wicket y Play! framework.
  • Tiene experiencia desarrollando con Ruby on Rails versiones 2 y 3 (ahora está probando la versión 4). Conoce Sinatra y hace scripts de shell en Ruby.
  • Domina Javascript (the good parts). Conoce en profundidad jQuery y algún framework MVC tipo Backbone. Puede programar en CoffeeScript.
  • Sabe montar una vista web: HTML5, CSS3 y usa algún preprocesador (SASS o LESS). También conoce HTML4, XHTML, CSS2 y toda esa basura obsoleta.
  • Es capaz de crear APIs REST dignas con Java o con Ruby.
  • Conoce el protocolo HTTP y sus principales particularidades.
  • Desarrolla para una plataforma movil: iOS o Android. Mejor, desarrolla para las dos.
  • Es capaz de configurar y mantener un servidor Unix/Linux (Apache, Tomcat, Pound, Bind, MySQL, Oracle y más).
  • Sabe lo que es el control de versiones. Domina Git.
  • Entiende por qué es interesante automatizar todos sus flujos de trabajo (como el despliegue de aplicaciones o el entorno de desarrollo).
  • Sabe que es importante testear el software y lo hace.
  • Es capaz de escribir un documento técnico de manera correcta y precisa.
  • Tiene dominio de inglés suficiente para ser capaz de entender documentación y puede participar en foros técnicos cuando es necesario para buscar ayuda.

No te asustes. Nadie en Trabe tiene este perfil y sabemos que es muy dificil encontrar a alguien que lo cumpla. Buscamos gente que venga a sumar y mejore nuestro equipo.

Lo que ofrecemos es un contrato fijo con un sueldo competitivo, seguro médico, horario flexible, jornada de verano, posibilidad de teletrabajar, oficina en el centro, ambiente distendido y mucho más.

Si crees que este es un trabajo para ti, no nos envíes un CV estándar (tu foto, tus datos y todo eso), envíanos un correo a rrhh@trabesoluciones.com y cuéntanos por qué te interesa el trabajo, qué experiencia tienes, qué te gusta, qué te disgusta y por qué. Si puedes enseñarnos algo que hayas hecho, mucho mejor. Puede ser un proyecto que has realizado en otra empresa y que sea público, un proyecto personal o una librería open-source. Dinos qué cumples del candidato ideal y no te tires de la moto: sabemos que nadie va a encajar al 100%.

Si tienes alguna duda pon un comentario en el post o envianos un correo. Gracias.

Prácticas de verano en Trabe

| | Comentarios

Buscamos a alumnos de últimos años de Ingeniería Informática o Grado en Informática que quieran aprender a desarrollar aplicaciones web en JEE o Ruby on Rails en Trabe. Lo que esperamos de vosotros es:

  • Que sepáis algo de Java, Spring, Hibernate y algún framework MVC.
  • Que sepáis algo de Ruby on Rails.
  • Que sepáis lo que es HTML5, CSS3 y JavaScript.

No hace falta que seáis unas máquinas (aunque estaría bien xD). La idea es que paséis el verano en nuestra oficina (en el centro de Coruña) trabajando con nosotros en proyectos reales, aprendiendo todo lo que hace falta para desarrollar una aplicación web. El horario y la remuneración lo negociaremos en función de vuestra experiencia previa (aunque no es necesaria, esto son unas prácticas) y disponibilidad. Tenemos bastante flexibilidad.

Si os interesa, no nos enviéis un CV estándar. Preferimos que nos contéis en un correo dirigido a rrhh@trabesoluciones.com qué estáis estudiando y si ya tenéis alguna experiencia profesional (ya hemos dicho que no es necesaria ¿verdad?), qué os interesa, qué os disgusta, qué queréis aprender, etc.

No os tiréis de la moto. Sed sinceros. Valoraremos tanto el conocimiento como el interés. Si podéis, enseñadnos algo que hayáis hecho antes en otras prácticas/empleo, un proyecto personal o alguna aportación a proyectos open source. Os dará puntos.

Esperamos vuestros correos.

Remote authentication with devise

| | Comentarios

Devise is great. It simplifies lots of tasks related to resource management: authentication, registration, confirmation, etc; and it does it in a clean and highly configurable way. But it is only this great if you are managing your resources locally. Devise has adapters only for models backed up with ActiveRecord or MongoId which means that if you’re using resources provided by an external webservice you can’t use Devise.

But don’t despair.

Extending Devise

First of all we have to get a basic idea of how Devise authenticates your resources. This explanation might be a bit rough so I’m going to use the following diagram to ease the explanation (kudos to asischao for his help).

The workflow of a request

  1. A request to authenticate a resource is received in the Rails app and it matches a route generated by devise_for.
  2. The request is handled (by default) by the SessionsController, provided by Devise, which delegates the authentication to Warden
  3. Warden uses one of the strategies provided by Devise to determine if the resource can be authenticated or not.

The output of this process is an authenticated resource. Or not.

So, from this list of steps it seems that we have the following spots to work on:

  • Configure our resource to enable remote authentication.
  • Create an strategy that authenticates the resources with the external webservice.

Configuring the resource

Lets assume that our resource is a PORO called User

User PORO
1
2
3
class User
  attr_accessor :id
end

Devise requires some functionallity that we usually have for free when using ActiveRecord resources. As this is not the case we have to do some plumbing: include some ActiveModel modules and extend the class using Devise::Models.

Preparation
1
2
3
4
5
6
7
class User
  include ActiveModel::Validations #required because some before_validations are defined in devise
  extend ActiveModel::Callbacks #required to define callbacks
  extend Devise::Models

  define_model_callbacks :validation #required by Devise
end

At this point we are ready to configure Devise.

Enable Devise
1
2
3
class User
  devise :remote_authenticatable
end

Authentication module

To understand a bit better what we are doing here take a look at the following Devise modules:

We have to create a module that performs at least three tasks:

  • Authenticate the resouce using the remote webservice.
  • Return an array of data that will be used to store a reference to the resource in the session.
  • Use this session data to re-build the resource.
Authenticate using the remote resource
1
2
3
4
5
6
7
8
9
10
11
module Devise
  module Models
    module RemoteAuthenticatable
      extend ActiveSupport::Concern

      def remote_authentication(authentication_hash)
        # Your logic to authenticate with the external webservice
      end
    end
  end
end

Devise::Models::RemoteAuthenticatable#remote_authentication will be used later (in the Warden strategy) to authenticate the resource using the remote webservice. This method performs almost the same function as Devise::Models::DatabaseAuthenticatable#valid_pasword? in the sense that they both have to return a resource instance if the creedentials are valid or false otherwise.

Serialize/Deserialize
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module Devise
  module Models
    module RemoteAuthenticatable
      extend ActiveSupport::Concern

      module ClassMethods
        def serialize_from_session(id)
          resource = self.new
          resource.id = id
          resource
        end

        def serialize_into_session(record)
          [record.id]
        end

      end
    end
  end
end

We overwrite Devise::Models::ClassMethods#serialize_into_session and Devise::Models::ClassMethods#serialize_from_session because their implementation is tied to resources using some kind of database backup. In this methods you just have to return an array with data that you’ll use later to re-build the resource instance.

The full code (with comments) of Devise::Models::RemoteAuthenticatable is on this gist

Creating an strategy

Strategies contains the logic used by Warden to authenticate users. They must define an authenticate! method, where the request will be processed. Inside this method you can take several actions:

  • halt! which halts the cascading of strategies.
  • fail! fails the strategy. Calls halt!
  • success! log in a user.
  • And other actions. Take a look at the documentation

Because of the conventions used by Devise, the strategy name has to be the same as the name of the module used to authenticate the resource.

Warden strategy for Devise
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  module Devise
    module Strategies
      class RemoteAuthenticatable < Authenticatable
        def authenticate!
          auth_params = authentication_hash
          auth_params[:password] = password

          resource = mapping.to.new

          return fail! unless resource

          if validate(resource){ resource.remote_authentication(auth_params) }
            success!(resource)
          end
        end
      end
    end
  end

The previous code is pretty straightforward. We create a new resource and using Devise::Models::RemoteAuthenticatable#remote_authentication we authenticate it. If the authentication succeeds we mark the request as valid with success!.

Gist with the code, and comments, of this strategy.

Putting everything together

So, to sum up, this solution is composed of:

  • Devise::Models::RemoteAuthenticatable, a module used by Devise to authenticate the resource.
  • Devise::Strategies::RemoteAuthenticatable, a class implementing a Warden strategy.

Finally, don’t forguet to configure Devise (in config/initializers/devise.rb) to use all the stuff we have done here : )

Configure Devise
1
2
3
4
  config.warden do |manager|
     manager.strategies.add(:remote, Devise::Strategies::RemoteAuthenticatable)
     manager.default_strategies(:scope => :user).unshift :remote
  end