2012/01/03

Intermedio

Afortunadamente he podido ligar el aprendizaje de erlang con las dos partes actuales de mi actividad profesional. Además de seguridad debo encargarme a mi pesar de administrar jira, algo totalmente no gratificante para mi. Quizas a otras personas les guste, pero yo lo detesto desde los más profundo de mi ser.

Ese rechazo se ha plasmado en el deseo de automatizar; dejémosle a las máquinas el trabajo sucio. ¿Dije antes "seguridad"? ¿Dije "jira"? ¿Dije "erlang"? ¡Buenísimo!


El otro día me enteré que jira ofrece una api [1] y me dije: Si pudiera mediante una api consultar las relaciones entre usuarios, grupos, roles y proyectos, tendría la posibilidad de detectar cualquier desviación de la configuración, como un cliente que haya sido asignado como administrador de un proyecto.


En esta ocasión, dejé el tdd de lado, es una vergüenza, pero es lo que hay.


La idea es poder consultar los grupos de usuarios y los usuarios con sus roles en cada proyecto y luego cruzarlos para detectar irregularidades


El proceso es muy sencillo:
  1. Generar un json según la llamada a efectuar [2]
  2. Llamar a jira
  3. Parsear el resultado
  4. Hacer los cruces
Primero hay que hacer login() para obtener un token, que es lo que se usa en las llamadas posteriores como autenticación.

La librería de erlang que use no soporta proxy con https, lo cual me dificultó al comienzo diagnosticar, pues necesitaba ver el tráfico y como jira usa https estaba afuera. Como logré establecer la comunicación exitosamente, no fue vital el problema. Con wireshark se pudo haber hecho teniendo la clave privada del servidor, lo cual no es posible en este caso.

Las llamadas a getGroup(), getProjectsNoSchemes() o getProjectWithSchemesById() son triviales y funcionan sin sorpresas, una vez que se ha podido parsear la respuesta.

En general es asi:

Json= make_json_getGroup({"Developers",Token}),

Url = "https://host.com/rpc/json-rpc/jirasoapservice-v2",

{ok, {{HttpVer, Code, Msg}, Headers, Body}} = 
http:request(post, { Url, [], "application/json", Json },  [], []),

{[{<<"id">>,_}|[{<<"result">>,{[{<<"name">>,_}| [ { <<"users">>, Users}]]}}|[{<<"jsonrpc">>,_}]]]}=
json_eep:json_to_term(Body),

En este caso, nos quedan los usuarios. Si nos interesara, nos podriamos quedar con el id, name y jsonrpc.

Esos dibujitos <<>> alrededor de los strings significan que en realidad son datos binarios y no debería confersarlo, pero me frenó casi una hora.

El problema fue cuando intenté obtener más datos de roles/usuarios por proyecto. Las firmas[3] de los métodos anteriores son:

RemoteGroup getGroup(java.lang.String token, java.lang.String groupName)
RemoteProject getProjectByKey(java.lang.String token, java.lang.String projectKey)
RemoteProjectRole getProjectRole(java.lang.String token, java.lang.Long id)

Pero la firma siguiente  es:

RemoteProjectRoleActors getProjectRoleActors(
   java.lang.String token,
   RemoteProjectRole projectRole,
   RemoteProject project 
)


Intenté ver via netbeans, que tiene un plugin para jira, el tráfico a ver si había algo que me ayudara, pero no hace las llamadas que necesitaba. Para esto use webscarab y le dije a netbeans que lo usara como proxy. Lo interesante es que netbeans no dijo nada, pese a recibir los certificados incorrectos del proxy en lugar de jira.com. Ya que estaba, subí el bug a netbeans[4].

Entonces, ¿cómo le paso un "RemoteProject"? Consideré hacer el conocido ataque de fuerza bruta de probar con key, "key", id, "id" para proyecto y rol pero tras dos combinaciones me aburrí, pensé en Murphy y me dije: "seguro que la solución correcta es la última" y fui directo a ella:

  Project = get_project_by_id({{token,Token},{project_id,"1234"}}),
 
  [ProjectRole|Roles] = get_project_roles({token,Token}),

  get_project_role_actors(

   {{token,Token},{project_role,ProjectRole},{project,Project}}
  ).

Más que sorpresa alivio me produjo que funcionara de una. No entiendo a quien se le ocurrió implementarlo asi. Alguien me preguntó si habia probado de sacarle algunos campos, ya que estoy enviando Project y ProyectRole:

{[{<<"key">>,<<"XXXX">>},
   {<<"description">>,null},
   {<<"url">>,<<"https://host.com/browse/XXXX">>},
   {<<"lead">>,<<"xxxxx.xxxxxxxx">>},
   {<<"permissionScheme">>,null},
   {<<"notificationScheme">>,null},
   {<<"issueSecurityScheme">>,null},
   {<<"projectUrl">>,null},
   {<<"name">>,<<"Xxxxx">>},
   {<<"id">>,<<"111111">>}]}. 

y

 {[{<<"name">>,<<"Administrators">>},
   {<<"id">>,111111},
   {<<"description">>,
    <<"A project role that represents administrators in a project">>}]}}.


y le contesté lo que supongo que es el motivo por el cual está hecho asi: "¿funciona? ¡LISTO!".

[1] https://developer.atlassian.com/display/JIRADEV/JIRA+JSON-RPC+Overview

[2] https://github.com/jchris/erlang-json-eep-parser

[3] http://docs.atlassian.com/rpc-jira-plugin/latest/com/atlassian/jira/rpc/soap/JiraSoapService.html

[4] http://netbeans.org/bugzilla/show_bug.cgi?id=206848

No hay comentarios:

Publicar un comentario