-
Blagoi Pavlov authoredBlagoi Pavlov authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
package main
import (
"encoding/json"
"log"
"net/http"
"strconv"
"time"
"github.com/golang-jwt/jwt/v4"
"github.com/gorilla/mux"
"github.com/yalp/jsonpath"
"go.uber.org/zap"
)
func RequestLogger(targetMux http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
targetMux.ServeHTTP(w, r)
Logger.Infow("",
zap.String("method", string(r.Method)),
zap.String("uri", string(r.RequestURI)),
zap.Duration("duration", time.Since(start)*1000),
)
})
}
func startServer(port *int) {
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/sendInvitation", sendInvitationPOST).Methods("POST")
router.HandleFunc("/createCredential", createCredentialPOST).Methods("POST")
router.HandleFunc("/options", optionsGET).Methods("GET")
router.HandleFunc("/isAlive", isAliveGet).Methods("GET")
portString := ":" + strconv.Itoa(*port)
log.Fatal(http.ListenAndServe(portString, RequestLogger(router)))
}
func sendInvitationPOST(w http.ResponseWriter, r *http.Request) {
// Get config
config, _ := getConfig()
// Authentication check
token, err := GetToken(r, config.inviteIdentityProviderOidURL)
if err != nil {
Logger.Error(err)
w.WriteHeader(401)
json.NewEncoder(w).Encode(err.Error())
return
}
// Authorization check
err = Authorize(r, config.inviteIdentityProviderOidURL, config.claimMappingURL, config.inviteAdminRolePath, config.inviteTokenContextPath, config.inviteRequiredClaims)
if err != nil {
Logger.Error(err)
w.WriteHeader(401)
json.NewEncoder(w).Encode(err.Error())
return
}
// Check if admin
adminRolePath := config.inviteAdminRolePath
adminRoles := config.adminRoles
tokenPayload, _ := json.Marshal(token.Claims.(jwt.MapClaims))
var tokenData interface{}
err = json.Unmarshal(tokenPayload, &tokenData)
roles, err := jsonpath.Read(tokenData, adminRolePath)
var adminRolesObjects []interface{}
err = json.Unmarshal([]byte(adminRoles), &adminRolesObjects)
isAdmin := false
for _, adminRoleObject := range adminRolesObjects {
for _, role := range roles.([]interface{}) {
if role.(string) == adminRoleObject.(string) {
isAdmin = true
}
}
}
if !isAdmin {
http.Error(w, "Missing admin role in token payload.", http.StatusBadRequest)
return
}
// Get body params
var jsonBody map[string]interface{}
err = json.NewDecoder(r.Body).Decode(&jsonBody)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
var bodyTemplateKeys map[string]interface{}
bodyTemplateKeys = jsonBody["templateKeyMap"].(map[string]interface{})
var selectedRoles ([]string)
for _, value := range jsonBody["selectedRoles"].(([]interface{})) {
selectedRoles = append(selectedRoles, string(value.(string)))
}
// Create data
var tokenDataMapping map[string]interface{}
json.Unmarshal([]byte(config.credentialMapping), &tokenDataMapping)
var data map[string]interface{}
json.Unmarshal([]byte(config.credentialDataTemplate), &data)
for key, value := range tokenDataMapping {
if tokenValue, found := tokenData.(map[string]interface{})[value.(string)]; found {
data[key] = tokenValue
} else {
data[key] = bodyTemplateKeys[key]
}
}
data["roles"] = selectedRoles
payload := make(map[string]interface{})
payload["userData"] = data
dataString, _ := json.Marshal(payload)
// Create invitation
credentialEndpoint := config.credentialEndpoint
qrCodeData, err := createInvitation(credentialEndpoint, string(dataString), token.Raw)
if err != nil {
Logger.Error(err)
w.WriteHeader(500)
json.NewEncoder(w).Encode(err.Error())
return
}
qrCodeContent, _ := json.Marshal(qrCodeData)
// Generate QR Code
qrCode, err := generateQR(string(qrCodeContent))
if err != nil {
Logger.Error(err)
w.WriteHeader(500)
json.NewEncoder(w).Encode(err.Error())
return
}
emailRecipient := bodyTemplateKeys["emailRecipient"]
// Send email
templateKeys := []string{}
var emailKeysJson []interface{}
json.Unmarshal([]byte(config.mailTemplateKeys), &emailKeysJson)
for _, keyObject := range emailKeysJson {
object := keyObject.(map[string]interface{})
templateKeys = append(templateKeys, object["key"].(string))
}
emailTemplate := config.mailTemplate
valueMap := make(map[string]string)
for _, key := range templateKeys {
if key == "qr" {
valueMap[key] = string(qrCode)
} else if _, ok := bodyTemplateKeys[key]; ok {
valueMap[key] = bodyTemplateKeys[key].(string)
}
}
err = sendEmail(emailTemplate, valueMap, emailRecipient.(string))
w.WriteHeader(http.StatusOK)
return
}
func createCredentialPOST(w http.ResponseWriter, r *http.Request) {
// Get config
config, _ := getConfig()
// Authentication check
token, err := GetToken(r, config.createIdentityProviderOidURL)
if err != nil {
Logger.Error(err)
w.WriteHeader(401)
json.NewEncoder(w).Encode(err.Error())
return
}
// Authorization check
err = Authorize(r, config.createIdentityProviderOidURL, config.claimMappingURL, config.createAdminRolePath, config.createTokenContextPath, config.createRequiredClaims)
if err != nil {
Logger.Error(err)
w.WriteHeader(401)
json.NewEncoder(w).Encode(err.Error())
return
}
// Get body params
var jsonBody map[string]interface{}
err = json.NewDecoder(r.Body).Decode(&jsonBody)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
var selectedRoles ([]string)
for _, value := range jsonBody["selectedRoles"].(([]interface{})) {
selectedRoles = append(selectedRoles, string(value.(string)))
}
// Check roles
adminRolePath := config.createAdminRolePath
tokenPayload, _ := json.Marshal(token.Claims.(jwt.MapClaims))
var tokenData interface{}
err = json.Unmarshal(tokenPayload, &tokenData)
roles, err := jsonpath.Read(tokenData, adminRolePath)
var finalRoles []string
var hasContent = false
for _, role := range roles.([]interface{}) {
for _, selectedRole := range selectedRoles {
if role.(string) == selectedRole {
finalRoles = append(finalRoles, role.(string))
hasContent = true
}
}
}
if !hasContent {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Create data
var tokenDataMapping map[string]interface{}
json.Unmarshal([]byte(config.credentialMapping), &tokenDataMapping)
var data map[string]interface{}
json.Unmarshal([]byte(config.credentialDataTemplate), &data)
for key, value := range tokenDataMapping {
if tokenValue, found := tokenData.(map[string]interface{})[value.(string)]; found {
data[key] = tokenValue
}
}
data["roles"] = finalRoles
payload := make(map[string]interface{})
payload["userData"] = data
dataString, _ := json.Marshal(payload)
// Create invitation
credentialEndpoint := config.credentialEndpoint
qrCodeData, err := createInvitation(credentialEndpoint, string(dataString), token.Raw)
if err != nil {
Logger.Error(err)
w.WriteHeader(500)
json.NewEncoder(w).Encode(err.Error())
return
}
qrCodeContent, _ := json.Marshal(qrCodeData)
// Generate QR Code
qrCode, err := generateQR(string(qrCodeContent))
if err != nil {
Logger.Error(err)
w.WriteHeader(500)
json.NewEncoder(w).Encode(err.Error())
return
}
w.Header().Set("Content-Type", "application/octet-stream")
w.Write(qrCode)
return
}
func optionsGET(w http.ResponseWriter, r *http.Request) {
// Get config
config, _ := getConfig()
w.Header().Set("Content-Type", "application/json")
options := make(map[string]interface{})
// Get roles
var roles []string
roleObjects, err := listRoles(config.claimMappingServiceURL)
if err != nil {
Logger.Error(err)
w.WriteHeader(500)
json.NewEncoder(w).Encode(err.Error())
return
}
for _, roleObject := range roleObjects {
role := roleObject.(map[string]interface{})
roles = append(roles, role["Role"].(string))
}
options["roleKeys"] = roles
// Get template email keys
var emailKeysJson []interface{}
json.Unmarshal([]byte(config.mailTemplateKeys), &emailKeysJson)
options["templateEmailKeys"] = emailKeysJson
json.NewEncoder(w).Encode(options)
return
}
func isAliveGet(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
return
}