API authorization through middlewares

When dealing with API authorization based on access tokens, permissions (user can see a list, can create an item, can delete one etc) and/or account types (administrator, moderator, normal user etc), I’ve seen the approach of checking requirements inside the HTTP handlers functions.

This post and attached source code do not handle security, API design, data storage patterns or any other best practices that do not aim directly at the main subject: Authorization through middlewares. All other code is just for illustrating the idea as a whole.

A classical way of dealing various authorization checks is to verify everything inside the handler function.

type User struct {
   Username    string
   Type        string
   Permissions uint8
}

var CanDoAction uint8 = 1

func tokenIsValid(token string) bool {
   // ...
   return true
}

func getUserHandler(c echo.Context) error {
   // Check authorization token
   token := c.Get("token").(string)
   if !tokenIsValid(token) {
      return c.NoContent(http.StatusUnauthorized)
   }

   user := c.Get("user").(User)

   // Check account type
   if user.Type != "admin" {
      return c.NoContent(http.StatusForbidden)
   }

   // Check permission for handler
   if user.Permissions&CanDoAction == 0 {
      return c.NoContent(http.StatusForbidden)
   }

   // Get data and send it as response
   data := struct {
      Username string `json:"username"`
   }{
      Username: user.Username,
   }

   return c.JSON(http.StatusOK, data)
}

The handler is doing more than its purpose. Continue reading API authorization through middlewares

Join domain on Ubuntu

It took me a while to find out how to join a domain (Microsoft Active Directory) on Ubuntu (16.04). I’ve adapted this guide to the following:

sudo apt update
sudo apt install ssh -y
wget https://github.com/BeyondTrust/pbis-open/releases/download/8.5.2/pbis-open-8.5.2.265.linux.x86_64.deb.sh
sudo chmod +x pbis-open-8.5.2.265.linux.x86_64.deb.sh
sudo ./pbis-open-8.5.2.265.linux.x86_64.deb.sh
sudo domainjoin-cli join <domain> <username>
sudo reboot #if necessary

This is not an universal solution. There are chances you’ll need extra steps depending on your network’s configuration.

Sending body on HTTP GET request

I’ve heard a few times “you can’t, it’s not possible to send a body on a request made with GET method”. Well… You can. You can send a body on a GET request and you can read the body. It’s against the standards and you should not do it, as it will mess your design. But technically, it can be done.

package main

import (
   "encoding/json"
   "io/ioutil"
   "log"
   "net/http"
)

func main() {
   http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
      body, err := ioutil.ReadAll(r.Body)
      if err != nil {
         log.Println(err)
         return
      }

      input := &struct {
         A string `json:"a"`
         B string `json:"b"`
      }{}
      if err := json.Unmarshal(body, input); err != nil {
         log.Println(err)
         return
      }

      data, err := json.Marshal(input)
      if err != nil {
         log.Println(err)
         return
      }
      w.Write(data)
   })

   log.Fatal(http.ListenAndServe(":8118", nil))
}
curl -X GET \
  http://localhost:8118 \
  -H 'content-type: application/json' \
  -d '{"a": "val1", "b":"val2"}'
{"a":"val1","b":"val2"}

Playing with PHP extensions: building a map

I’ve ran into PHP-CPP, a C++ library which helps you build your own PHP extensions in an easier way than writing them from scratch. And I decided to play a little bit. It has good documentation and examples.

Installing is not always out of the box depending on the environment. I like to keep things clean on my working machines so I wanted to have everything in a Docker container, but I quickly ran into an issue installing the library. Fortunately, I’ve found a solution pretty fast.

The first idea that came into my mind was a simple map. Nothing special, I’m not bringing any improvements, I just wanted to convert the following into an extension. Continue reading Playing with PHP extensions: building a map

Race condition on Echo context with GraphQL in Go

Given an API setup with GraphQL and Echo, a colleague ran into a race condition situation. There was a concurrent read/write issue on Echo’s context. GraphQL runs its resolvers in parallel if set so, and when context is shared between resolvers, things can go wrong.

I took a look into Echo’s context implementation and I saw a simple map is used for Get/Set.

For every API call, a handle functions is given an Echo context and executes the GraphQL schema with the specified context.

func handle(c echo.Context) error {
 schema, err := gqlgo.ParseSchema(
  ...
  gqlgo.MaxParallelism(10),
 )

 schema.Exec(
  c,
  ...
 )
}

My solution was to use a custom context which embeds the original one and uses a concurrent map instead of Echo’s. Continue reading Race condition on Echo context with GraphQL in Go