Category Archives: Inne

Google OAuth 2.0 authentication in Phoenix

Let’s create new Phoenix application:

mix phoenix.new app

Dependencies

We are going to use oauth2 library in our application. First we need to update our dependencies in mix.exs file:

# mix.exs
defmodule App.Mixfile do
  # ...
  def application do
    [mod: {App, []},
     applications: [:phoenix, :phoenix_html, :cowboy, :logger,
                    :phoenix_ecto, :postgrex, :oauth2]]
  end
  # ...
  defp deps do
    [{:phoenix, "~> 1.0.2"},
     {:phoenix_ecto, "~> 1.1"},
     {:postgrex, ">= 0.0.0"},
     {:phoenix_html, "~> 2.1"},
     {:phoenix_live_reload, "~> 1.0", only: :dev},
     {:cowboy, "~> 1.0"},
     {:oauth2, "~> 0.3"}
   ]
  end
end

Then we update dependencies with:

mix deps.get

Routes

Now we are good with dependencies, so it’s time to add routes:

# web/router.ex
defmodule App.Router do
  # ...
  scope "/auth", App do
    pipe_through :browser # Use the default browser stack

    get "/:provider", AuthController, :index
    get "/:provider/callback", AuthController, :callback
  end
  # ...
end

AuthController

Next thing is to implement AuthController

# web/controllers/auth_controller.ex
defmodule App.AuthController do
  use App.Web, :controller

  def index(conn, %{"provider" => provider}) do
    redirect conn, external: authorize_url!(provider)
  end

  def callback(conn, %{"provider" => provider, "code" => code}) do
    token = get_token!(provider, code)
    user = get_user!(provider, token)

    conn
    |> put_session(:current_user, user)
    |> put_session(:access_token, token.access_token)
    |> redirect(to: "/")
  end

  defp authorize_url!("google") do
    Google.authorize_url!(scope: "email profile")
  end

  defp authorize_url!(_) do
    raise "No matching provider available"
  end

  defp get_token!("google", code) do
    Google.get_token!(code: code)
  end

  defp get_token!(_, _) do
    raise "No matching provider available"
  end

  defp get_user!("google", token) do
    user_url = "https://www.googleapis.com/plus/v1/people/me/openIdConnect"
    OAuth2.AccessToken.get!(token, user_url)
  end
end

Authentication strategy

Last thing to implement is Google module

# web/oauth/google.ex
defmodule Google do
  use OAuth2.Strategy

  alias OAuth2.Strategy.AuthCode

  def client do
    OAuth2.Client.new([
      strategy: __MODULE__,
      client_id: System.get_env("CLIENT_ID"),
      client_secret: System.get_env("CLIENT_SECRET"),
      redirect_uri: System.get_env("REDIRECT_URI"),
      site: "https://accounts.google.com",
      authorize_url: "https://accounts.google.com/o/oauth2/auth",
      token_url: "https://accounts.google.com/o/oauth2/token"
    ])
  end

  def authorize_url!(params \\ []) do
    OAuth2.Client.authorize_url!(client(), params)
  end

  def get_token!(params \\ [], headers \\ []) do
    OAuth2.Client.get_token!(client(), params, headers)
  end

  # strategy callbacks

  def authorize_url(client, params) do
    AuthCode.authorize_url(client, params)
  end

  def get_token(client, params, headers) do
    client
    |> put_header("Accept", "application/json")
    |> AuthCode.get_token(params, headers)
  end
end

Basically we finished implementing authentication but we see no difference in our application. At least let’s add button and display information after we are logged.

Let’s start from replacing content from web/templates/page/index.html.eex with:

<!-- web/templates/page/index.html.eex -->
<%= if @current_user do %>
  <h2>Welcome, <%= @current_user["name"] %>!</h2>
<% else %>
  <%= link to: auth_path(@conn, :index, "google"), class: "btn btn-primary" do %>
    Sign in with Google
  <% end %>
<% end %>

Last changes we introduce in PageController

# web/controllers/page_controller.ex
defmodule App.PageController do
  use App.Web, :controller

  def index(conn, _params) do
    conn
    |> assign(:current_user, get_session(conn, :current_user))
    |> render "index.html"
  end
end

Result

Before authentication we should see:

before_authentication

and after:

after_authentication

Resources

In implementing Google OAuth 2.0 authentication I found helpful source code from repositories:

Wspomnienia z Craft Conf 2015

23-24 kwietnia miałem okazję być na Craft Conf 2015 w Budapeszcie. Konferencja została zorganizowana w Várkert Bazar. Miejsce okazało się strzałem w dziesiątkę – przestronne, w uroczym otoczeniu.

Prezentacje zostały podzielone na 4 ścieżki. Dla mnie największą atrakcją był Garage – świetny pomysł na wykorzystanie parkingu podziemnego. Jeśli chodzi o same prezentacje, to mam kilka ulubionych, na których byłem:

  • Dan North, Jessica Kerr, Keynote: Complexity is Outside the Code
    http://www.ustream.tv/recorded/61439914
    Bardzo dobra prezentacja rozpoczynająca konferencję. Dan i Jessica przedstawili złożoność analizując jej dwa obszary: techniczny i ludzki. W części dotyczącej technologii poruszyli rozwój architektury systemów informatycznych i problemy z nimi związane. Następnie przeszli przez codzienne życie programisty – jak wiele rzeczy trzeba przyswoić i jak wygląda proces zdobywania wiedzy. Jeśli chodzi o część związaną z ludźmi, to trzeba pamiętać, że projekt to praca zespołowa – każdy ma inne umiejętności, które mogą być cenne dla zespołu.
  • Katherine Daniels, Devops for Everyone
    Katherine podczas swojej prezentacji opowiedziała o tym jak wygląda praca w Etsy. Spośród stosowanych praktyk bardzo spodobały mi się:„We’re all in charge of devops” oraz Engineering Mixers, czyli spotkania programistów z różnych działów służące lepszemu poznaniu się i wymianie wiedzy.
  • Alf Rehn, Closing Keynote: How To Save Innovation From Itself
    http://www.ustream.tv/recorded/61452853
    Świetna prezentacja! Alf opowiedział o złudzeniu innowacji. Kalifornia przeżywa jedną z większych suszy w historii, ale i tak wiele firm/przedsięwzięć z Doliny Krzemowej skupia się na rozwiązywaniu nieistniejących problemów – „Fuck water. Fuck nature. Gimme my kitty”.
  • Neha Narula, Splitting and Replicating Data For Fast Transactions – Don’t Give Up On Serializability Just Yet!
    http://www.ustream.tv/recorded/61479586
    Bardzo ciekawa prezentacja związana z transakcjami w rozproszonych bazach danych.
  • Tammer Saleh, Microservice AntiPatterns
    http://www.ustream.tv/recorded/61486500
    Dobra prezentacja. Wiele przydatnych wskazówek.
  • Jessica Kerr, Contracts and Clojure: The Best-Yet Compromise Between Types and Tests
    http://www.ustream.tv/recorded/61488888

Refactoring legacy code

Recently I’m trying to upgrade one big project from Ruby 1.8.7 to 1.9.3.
It is bumpy road but here are some thoughts gathered during this time:

1. Make small steps – especially when pushing those changes to production. You’ll never know what are going to break.
2. When changing API endpoint find every call to that endpoint. Record HTTP requests & responses and test them.
3. Improve test coverage. The more good specs you have, the better.
4. Update only necessary gems to get your code working on Ruby 1.9.3.
5. Set up Continuous Integration server to run specs on both Ruby versions: 1.8.7 & 1.9.3.
6. Analyze & understand business logic in code. Use metric_fu, simplecov to know more about code.
7. Delete unused code.

FTP server on OS X 10.8.5

On my OS X 10.8.5 I tried to do specific task: I want to set up FTP server where user has full access to that specific place — he can upload/download and remove files without any problems. After spending some time with this I came to solution to create new user in system and set configuration of /etc/ftpd.conf to sth like that:

chroot REAL /path/to/directory
modify all
upload all

To start & stop FTP server I used those commands

sudo -s launchctl load -w /System/Library/LaunchDaemons/ftp.plist
sudo -s launchctl unload -w /System/Library/LaunchDaemons/ftp.plist

Those resources were helpful for me:
Start an FTP or SFTP Server in Mac OS X
OS X: anonymous ftp directory on Mountain Lion

Dynamic aliases in zsh

I work with project which consists of many subdirectories. When I wanted go to specific directory, I went to the root of project and then changed to specific directory. I decided to optimize this a little bit.

My first approach looked like that:

alias p='cd /path/to/project'
alias subdirectory1='cd /path/to/project/subdirectory1'
alias subdirectory2='cd /path/to/project/subdirectory2'
...
...

It came to my mind that I can define dynamically all necessary aliases. I added to my .zshrc following lines:

for folder in `ls /path/to/project`;
  do alias $folder="cd /path/to/project/$folder";
done;

Of course this solution add small overhead when loading .zshrc but it is much simpler and easier to maintain.

Nginx compilation from sources

Check sources on: http://nginx.org/download/

wget http://nginx.org/download/nginx-1.5.0.zip
unzip nginx-1.5.0.zip
cd nginx-1.5.0
./configure --prefix ~/.nginx
make
make install

Handling Heroku PostgreSQL Dev row limit

Free Heroku PostgreSQL Dev database has row limit: 10,000 rows.
Recently, I got following error in Rails app:
ActiveRecord::StatementInvalid (PG::Error: ERROR: permission denied for relation ...)

I started browsing the Internet and I found this entry at StackOverflow. After checking database:

SELECT schemaname,relname,n_live_tup 
  FROM pg_stat_user_tables 
  ORDER BY n_live_tup DESC;

Truncating tables did a job 🙂

TRUNCATE TABLE name;
TRUNCATE TABLE name CASCADE;

tmux: początki

Dzisiaj postanowiłem bliżej zapoznać się z tmuksem.
Czasami przydaje się podzielić okno terminala na kilka mniejszych 🙂

Od razu zacząłem dopasowywać tmuksa do swoich potrzeb. Najpierw zmieniłem prefix, pierwszy skrót klawiaturowy w sekwencji skrótów, które uruchamiają dane polecenie.

unbind C-b 
set -g prefix C-w 

Korzystam dosyć dużo z vima, więc dzielenie okien pod skrótami v (w pionie), s (w poziomie) jest dla mnie naturalne.

unbind %
bind s split-window -v
bind v split-window -h

Jeszcze drobne usprawnienie w przechodzeniu po oknach (również zaczerpnięte z vima). Częściej korzystam ze strzałek (ze względu na innne skróty klawiaturowe), ale HJKL też się przydaje.

setw -g mode-keys vi
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
bind-key -r C-h select-window -t :-
bind-key -r C-l select-window -t :+

To tyle na początek. Myślę, że w najbliższym czasie zacznę się zapoznawać z innymi funkcjonalnościami tmuksa.
Love, hate, & tmux
TMUX – The Terminal Multiplexer

Managing Multiple Environments for an App

https://github.com/heroku/heroku/issues/169
https://devcenter.heroku.com/articles/multiple-environments#starting-from-scratch

git config heroku.remote production

Prosta funkcja w zsh

Mało wyszukany przykład, ale jak stworzyć katalog i od razu do niego wejść.

Do .zshrc wystarczy dodać np. taką linijkę:

c () {
  mkdir "$1" && cd "$1"
}