Skip to main content

Go Native

  • Postgresql is used.
  • Imports.
import (
"database/sql"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"math/rand"
"net/http"
"strings"
"time"

"github.com/dgrijalva/jwt-go"
"github.com/gorilla/mux"
"github.com/lib/pq"
)
  • Constants
const oidcAuthEndpoint = "https://tenantname.aws1.test1.com/auth/realms/{tenantname}/protocol/openid-connect/auth"
const oidcClient = "openidtestclient"
const oidcClientSecret = "0086d90a-221f-431c-ad35-741e6599bf6c"
const oidcTokenURI = "https://tenantname.aws1.test1.com/auth/realms/{tenantname}/protocol/openid-connect/token"
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  • Used custom types
type user struct {
Email string `json:"email"`
}
type loginData struct {
Token string `json:"token"`
User user `json:"user"`
}
type oidcResponseData struct {
ClientID string `json:"client_id"`
AuthURL string `json:"auth_url"`
ComposedURL string `json:"composed_url"`
}

/auth/oidc (GET)

func oidchandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*") // Cors için
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Cookie,Set-Cookie")
if r.Method == http.MethodOptions {
return
}
redirectURL := r.URL.Query().Get("redirect_uri") // Query param'dan redirect_uri'ı al
nonce := genNonce(8)
url := fmt.Sprintf("%s?client_id=%s&redirect_uri=%s&scope=openid&response_type=code&response_mode=query&nonce=%s", oidcAuthEndpoint, oidcClient, redirectURL, nonce)
// url oluşturulur
data := oidcResponseData{AuthURL: oidcAuthEndpoint, ClientID: oidcClient, ComposedURL: url} // response struct

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(data)
}
//Yardımcı getNonce fonksiyonu random string üretmeye yarıyor.
func genNonce(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return string(b)
}

/auth/code (POST)

func codehandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*") // Cors için
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Cookie,Set-Cookie")
if r.Method == http.MethodOptions {
return
}
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
var data map[string]string // Request bilgisi map'e alınır
json.Unmarshal([]byte(body), &data)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

// Token endpoint'ine istek parametreleri ayarlanır

url := oidcTokenURI
method := "POST"

payload := strings.NewReader(fmt.Sprintf("client_id=%s&redirect_uri=%s&grant_type=authorization_code&client_secret=%s&code=%s", oidcClient, data["redirect_uri"], oidcClientSecret, data["code"]))

client := &http.Client{}
req, err := http.NewRequest(method, url, payload)

if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

res, err := client.Do(req) // Post request token endpoint'ine atılır

var result map[string]string
json.Unmarshal([]byte(resBody), &result)

idToken := result["id_token"]
if idToken == "" {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}

parser := jwt.Parser{}
claims := jwt.MapClaims{}
parser.ParseUnverified(idToken, claims) // token parse edilip içeriği claim's e geliyor

var email string // Databaseden buraya kopyalamaya çalışacağız user email'ini
token := jwt.New(jwt.SigningMethodHS256) // session token'ımız oluşturulmaya başlanır
newTokenClaims := token.Claims.(jwt.MapClaims)
newTokenClaims["exp"] = time.Now().Add(time.Minute * 30).Unix()

// Bu email ile kullanıcı veri tabanında var mı diye bakılır
sqlStatement := `SELECT * FROM users WHERE email=$1;`
row := db.QueryRow(sqlStatement, claims["email"].(string))
switch err := row.Scan(&email); err { // Bu fonksiyon döndüğü değere göre işlem başarılı veya değil
case sql.ErrNoRows: // Böyle bir email ile kayıt yoksa
sqlStatement := `INSERT INTO users (email) VALUES ($1)`
_, err = db.Exec(sqlStatement, claims["email"].(string))
if err != nil {
panic(err)
}
newTokenClaims["email"] = claims["email"].(string)
email = claims["email"].(string) // response içine koymak için bunu dolduruyoruz
case nil: // başarılı şekilde email değişkenine databaseden kopyalandı
newTokenClaims["email"] = email
default: // Başka bir hata olursa
panic(err)
}

var hmacSampleSecret []byte
hmacSampleSecret = []byte("jwtsecretkey")
tokenString, err := token.SignedString(hmacSampleSecret) // Token imzalama
user := user{Email: email}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
resData := loginData{ // response bilgisi
Token: tokenString,
User: user}

json.NewEncoder(w).Encode(resData)

}