new dnshookcmd. added email on client-side.

parent 6b38e067
......@@ -133,12 +133,13 @@ func (c *Client) updateClientKeyAfterRegistration(kid string) error {
return crypto.WriteKeyToFile(c.key, c.config.Client.KeyFile)
}
func (c *Client) CreateAndSaveIdentityAuthz(id, locale string) (*models.IdentityAuthz, error) {
func (c *Client) CreateAndSaveIdentityAuthz(id, locale, email string) (*models.IdentityAuthz, error) {
authz, err := c.postNewIdentityAuthz(id, locale)
if err != nil {
return nil, err
}
authz.Email = email
err = utils.ToYamlFile(authz, c.config.AuthzDir+"/"+id+".authz.yaml")
if err != nil {
return nil, err
......@@ -165,10 +166,18 @@ func (c *Client) CreateAcmeChallenge(token string) (string, error) {
}
func (c *Client) GetIdentityAuthz(id string) (*models.IdentityAuthz, error) {
existingAuthz, err := utils.AuthzFromYamlFile(c.config.AuthzDir, id)
if err != nil {
existingAuthz = &models.IdentityAuthz{Email: ""}
}
authzAtAuthority, err := c.getIdentityAuthz(id)
if err != nil {
return nil, err
}
authzAtAuthority.Email = existingAuthz.Email
err = utils.ToYamlFile(authzAtAuthority, c.config.AuthzDir+"/"+id+".authz.yaml")
if err != nil {
return nil, err
......@@ -190,6 +199,9 @@ func (c *Client) GetIdentity(id string) (*models.Identity, error) {
return nil, err
}
authz, err := utils.AuthzFromYamlFile(c.config.AuthzDir, id)
identity.Email = authz.Email
err = utils.ToYamlFile(identity, c.config.AuthzDir+"/"+id+".yaml")
if err != nil {
return nil, err
......
......@@ -9,7 +9,7 @@ import (
gurl "net/url"
"gitlab.com/denic-id/aim-client/dns"
"gitlab.com/denic-id/aim-client/hooks"
yaml "gopkg.in/yaml.v2"
......@@ -48,11 +48,13 @@ func init() {
create := app.Command("create", "Create a resource")
createAuthz := create.Command("authz", "Create a new identity authz")
createAuthz.Arg("id", "the identitfier which should be created.").Required().StringVar(&id)
createAuthz.Arg("locale", "the desired locale for the id").Default("en").StringVar(&locale)
createAuthz.Flag("locale", "the desired locale for the id").Short('l').Default("en").StringVar(&locale)
createAuthz.Flag("email", "the mail address of the identity owner").Short('m').Default("").StringVar(&email)
createID := create.Command("id", "Setup everything for a new identity.")
createID.Arg("id", "the identitfier which should be created.").Required().StringVar(&id)
createID.Arg("locale", "the desired locale for the id").Default("en").StringVar(&locale)
createID.Flag("locale", "the desired locale for the id").Short('l').Default("en").StringVar(&locale)
createID.Flag("email", "the mail address of the identity owner").Short('m').Default("").StringVar(&email)
activate := app.Command("activate", "Signals that the ACME challenge for the id is set up.")
activateID := activate.Command("id", "Signals that the ACME challenge for the id is set up.")
......@@ -179,7 +181,8 @@ func InitAgent() {
AimURL: "https://id.staging.denic.de/aim/v1",
AuthzDir: "",
AuthorityURL: "https://id.staging.denic.de",
DnsCmd: "",
DnsHookCmd: "",
MailHookCmd: "",
}
}
name := askForValue("Name for the agent", existingConfig.Client.Name)
......@@ -190,7 +193,8 @@ func InitAgent() {
aimurl := askForValue("AIM endpoint at the authority ", existingConfig.AimURL)
authorityURL := askForValue("BaseURL of the authority", existingConfig.AuthorityURL)
authzdir := askForValue("Directory where identity authz are stored", existingConfig.AuthzDir)
dnsCmd := askForValue("Command to be invoked for setting up dns records.", existingConfig.DnsCmd)
dnsCmd := askForValue("Command to be invoked for setting up dns records.", existingConfig.DnsHookCmd)
mailCmd := askForValue("Command to be invoked for sending a mail to the identity owner", existingConfig.MailHookCmd)
appconfig := config.AppConfig{
Client: &config.ClientConfig{
......@@ -203,7 +207,8 @@ func InitAgent() {
AimURL: aimurl,
AuthzDir: authzdir,
AuthorityURL: authorityURL,
DnsCmd: dnsCmd,
DnsHookCmd: dnsCmd,
MailHookCmd: mailCmd,
}
fmt.Println("Creating directories.")
......@@ -282,7 +287,7 @@ func CreateIdAuthz() {
c, err := newClient()
checkError(err)
_, err = c.CreateAndSaveIdentityAuthz(id, locale)
_, err = c.CreateAndSaveIdentityAuthz(id, locale, email)
checkError(err)
GetIdAuthz()
......@@ -293,7 +298,7 @@ func SetupAcme() {
c, err := newClient()
checkError(err)
if len(c.GetConfig().DnsCmd) < 1 {
if len(c.GetConfig().DnsHookCmd) < 1 {
fmt.Println("no dnsCommand is configured. Exit.")
os.Exit(1)
}
......@@ -304,8 +309,8 @@ func SetupAcme() {
fmt.Println("Setting up ACME DNS for %s", authz.Identifier)
challenge, err := c.CreateAcmeChallenge(authz.Challenge.Token)
checkError(err)
dnsCmd := dns.NewDNSCommand(c.GetConfig().DnsCmd, "acme", authz.Identifier, challenge)
fmt.Printf("Invoking cmd: %s %s %s %s\n", c.GetConfig().DnsCmd, "acme", authz.Identifier, challenge)
dnsCmd := hooks.NewDNSCommand(c.GetConfig().DnsHookCmd, "_acme-challenge."+authz.Identifier, "TXT", challenge)
fmt.Printf("Invoking cmd: %s %s %s %s\n", dnsCmd.ProgramPath, dnsCmd.Name, dnsCmd.RType, dnsCmd.RData)
out, err := dnsCmd.Invoke()
checkError(err)
fmt.Println(string(out))
......@@ -316,7 +321,7 @@ func SetupOpenID() {
c, err := newClient()
checkError(err)
if len(c.GetConfig().DnsCmd) < 1 {
if len(c.GetConfig().DnsHookCmd) < 1 {
fmt.Println("no dnsCommand is configured. Exit.")
os.Exit(1)
}
......@@ -329,8 +334,8 @@ func SetupOpenID() {
data := fmt.Sprintf("v=OID1;iss=%s://%s", u.Scheme, u.Hostname())
fmt.Println("Setting up openid DNS for %s", authz.Identifier)
dnsCmd := dns.NewDNSCommand(c.GetConfig().DnsCmd, "openid", authz.Identifier, data)
fmt.Printf("Invoking cmd: %s %s %s %s\n", dnsCmd.ProgramPath, dnsCmd.Action, dnsCmd.ID, dnsCmd.Value)
dnsCmd := hooks.NewDNSCommand(c.GetConfig().DnsHookCmd, "_openid."+authz.Identifier, "TXT", data)
fmt.Printf("Invoking cmd: %s %s %s %s\n", dnsCmd.ProgramPath, dnsCmd.Name, dnsCmd.RType, dnsCmd.RData)
out, err := dnsCmd.Invoke()
checkError(err)
......
......@@ -5,7 +5,8 @@ type AppConfig struct {
AimURL string `json:"aimURL" yaml:"aimURL"`
AuthzDir string `json:"authzDir" yaml:"authzDir"`
AuthorityURL string `json:"authorityURL" yaml:"authorityURL"`
DnsCmd string `json:"dnsCommand" yaml:"dnsCommand"`
DnsHookCmd string `json:"dnsHookCmd" yaml:"dnsHookCmd"`
MailHookCmd string `json:"mailHookCmd" yaml:"mailHookCmd"`
}
type ClientConfig struct {
......
#!/bin/bash
action=$1
id=$2
data=$3
rname=$1
rtype=$2
rdata=$3
DOMAIN=iostat.de
# get the dns label without domain and trailing dot
ID=${id%${DOMAIN}}
ID=${ID%.}
RNAME=${rname%${DOMAIN}}
RNAME=${RNAME%.}
usage() {
echo "$0 <action> <id> <data>"
echo " actions: "
echo " acme - setup an acme dns record"
echo " openid - setup the openid dns record"
echo
echo " id - the identifier"
echo " data - the value for the TXT record"
echo "$0 <name> <type> <data>"
echo " name - The name of the DNS record. Example: _acme-challenge.myid.example.org"
echo " type - The type of the RR. Example: TXT"
echo " data - The data for the record. Example: \"lshenl1233-jslfj\""
exit 1
}
case $action in
acme) prefix="_acme-challenge";;
openid) prefix="_openid";;
*) usage;;
esac
RECORD_ID=$(doctl compute domain records list ${DOMAIN} --no-header | grep "${prefix}.${ID}" | awk '{print $1}')
RECORD_ID=$(doctl compute domain records list ${DOMAIN} --no-header | grep "${RNAME}" | awk '{print $1}')
[[ -n "${RECORD_ID}" ]] && {
[[ $(echo ${RECORD_ID} | wc -w) -gt 1 ]] && { echo "More than one record exists for ${prefix}.${id}. Please cleanup first."; exit 1;}
[[ $(echo ${RECORD_ID} | wc -w) -gt 1 ]] && { echo "More than one record exists for ${RNAME}. Please cleanup first."; exit 1;}
echo "we need to update record ${RECORD_ID}"
doctl compute domain records update ${DOMAIN} --record-id=${RECORD_ID} --record-type=TXT --record-ttl=300 --record-name=${prefix}.${ID} --record-data=\"${data}\"
doctl compute domain records update ${DOMAIN} --record-id=${RECORD_ID} --record-type=${rtype} --record-ttl=300 --record-name=${RNAME} --record-data=\"${rdata}\"
[[ $? -eq 0 ]] && { exit 0; } || { echo "Failed to update record!"; exit 1; }
} || {
echo "we need to create a new record"
doctl compute domain records create ${DOMAIN} --record-type=TXT --record-ttl=300 --record-name=${prefix}.${ID} --record-data=\"${data}\"
doctl compute domain records create ${DOMAIN} --record-type=${rtype} --record-ttl=300 --record-name=${RNAME} --record-data=\"${rdata}\"
[[ $? -eq 0 ]] && { exit 0; } || { echo "Failed to create record!"; exit 1; }
}
# check if the record exists
package dns
package hooks
import (
"os/exec"
......@@ -6,30 +6,30 @@ import (
type DNSCommand struct {
ProgramPath string
Action string
ID string
Value string
Name string
RType string
RData string
}
// NewDNSCommand creates a new DnsCommand with the passed params.
func NewDNSCommand(prog, action, id, value string) *DNSCommand {
func NewDNSCommand(prog, name, rtype, rdata string) *DNSCommand {
if len(prog) < 1 ||
len(action) < 1 ||
len(id) < 1 ||
len(value) < 1 {
len(name) < 1 ||
len(rtype) < 1 ||
len(rdata) < 1 {
return nil
}
return &DNSCommand{
ProgramPath: prog,
Action: action,
ID: id,
Value: value,
Name: name,
RType: rtype,
RData: rdata,
}
}
func (dnsCmd *DNSCommand) Invoke() ([]byte, error) {
cmd := exec.Command(dnsCmd.ProgramPath, dnsCmd.Action, dnsCmd.ID, dnsCmd.Value)
cmd := exec.Command(dnsCmd.ProgramPath, dnsCmd.Name, dnsCmd.RType, dnsCmd.RData)
return cmd.Output()
}
package hooks
import (
"os/exec"
)
// MailCommand stores the attributes for invoking the hook which sends mails.
type MailCommand struct {
ProgramPath string
Identifier string
EmailAddress string
AgentName string
MagicURL string
Locale string
}
// NewMailCommand creates a new MailCommand with the passed params.
func NewMailCommand(prog, id, address, agentName, magicURL, locale string) *MailCommand {
if len(prog) < 1 ||
len(id) < 1 ||
len(address) < 1 ||
len(agentName) < 1 ||
len(magicURL) < 1 ||
len(locale) < 1 {
return nil
}
return &MailCommand{
ProgramPath: prog,
Identifier: id,
EmailAddress: address,
AgentName: agentName,
MagicURL: magicURL,
Locale: locale,
}
}
// Invoke runs the MailCommand
func (mailCmd *MailCommand) Invoke() ([]byte, error) {
cmd := exec.Command(mailCmd.ProgramPath, mailCmd.Identifier, mailCmd.EmailAddress, mailCmd.AgentName, mailCmd.MagicURL, mailCmd.Locale)
return cmd.Output()
}
......@@ -25,18 +25,19 @@ type IdentityAuthzRequest struct {
// IdentityAuthz represents the database and application model for an identity authorization.
type IdentityAuthz struct {
ID int64 `json:"id"`
Identifier string `json:"identifier"`
Expires time.Time `json:"expires"`
Status string `json:"status"`
Challenge Challenge `json:"challenge"`
ID int64 `json:"id" yaml:"id"`
Identifier string `json:"identifier" yaml:"identifier"`
Email string `json:"-" yaml:"email,omitempty"`
Expires time.Time `json:"expires" yaml:"expires"`
Status string `json:"status" yaml:"status"`
Challenge Challenge `json:"challenge" yaml:"challenge"`
}
// Challenge represents the database and application model for a challenge that is embedded in the IdentityAuthz.
type Challenge struct {
URL string `json:"url"`
Token string `json:"token"`
Validated *time.Time `json:"validated"`
URL string `json:"url" yaml:"url"`
Token string `json:"token" yaml:"token"`
Validated *time.Time `json:"validated" yaml:"validated"`
}
// Identity represents the database and application model for an identity.
......@@ -44,6 +45,7 @@ type Identity struct {
Identifier string `json:"identifier" yaml:"identifier"`
Subject string `json:"sub" yaml:"sub"`
Locale string `json:"locale" yaml:"locale"`
Email string `json:"-" yaml:"email,omitempty"`
URL string `json:"url" yaml:"url"`
URLExpires int64 `json:"url_expire" yaml:"urlExpire"`
AgentIssuerURL string `json:"agentIssuerURL" yaml:"agentIssuerURL"`
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment