Skip to content

Commit

Permalink
[CLOUDTRUST-2107] Register API
Browse files Browse the repository at this point in the history
  • Loading branch information
fperot74 authored and harture committed Jan 23, 2020
1 parent cfe55d5 commit 4ebccc6
Show file tree
Hide file tree
Showing 21 changed files with 1,592 additions and 37 deletions.
39 changes: 24 additions & 15 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion README.md
Expand Up @@ -41,6 +41,7 @@ Key | Description | Default value
internal-http-host-port | HTTP server listening address | 0.0.0.0:8888
management-http-host-port | HTTP server listening address | 0.0.0.0:8877
account-http-host-port | HTTP server listening address | 0.0.0.0:8866
register-http-host-port | HTTP server listening address | 0.0.0.0:8855


### Keycloak
Expand All @@ -66,12 +67,17 @@ Some parameters can be overridden with following ENV variables:

ENV Variable | Parameter
--- | -----------
CT_BRIDGE_REGISTER_USERNAME | register-techuser-username
CT_BRIDGE_REGISTER_PASSWORD | register-techuser-password
CT_BRIDGE_REGISTER_CLIENT_ID | register-techuser-client-id
CT_BRIDGE_DB_AUDIT_RW_USERNAME | db-audit-rw-username
CT_BRIDGE_DB_AUDIT_RW_PASSWORD | db-audit-rw-password
CT_BRIDGE_DB_AUDIT_RO_USERNAME | db-audit-ro-username
CT_BRIDGE_DB_AUDIT_RO_PASSWORD | db-audit-ro-password
CT_BRIDGE_DB_CONFIG_USERNAME | db-config-username
CT_BRIDGE_DB_CONFIG_PASSWORD | db-config-password
CT_BRIDGE_DB_USERS_USERNAME | db-users-username
CT_BRIDGE_DB_USERS_PASSWORD | db-users-password
CT_BRIDGE_INFLUX_USERNAME | influx-username
CT_BRIDGE_INFLUX_PASSWORD | influx-password
CT_BRIDGE_SENTRY_DSN | sentry-dsn
Expand Down Expand Up @@ -145,7 +151,7 @@ correlation_id:<correlation_id>

## Tests

Gomock is used to automatically genarate mocks. See the Cloudtrust [Gitbook](https://cloudtrust.github.io/doc/chapter-godevel/testing.html) for more information.
Gomock is used to automatically generate mocks. See the Cloudtrust [Gitbook](https://cloudtrust.github.io/doc/chapter-godevel/testing.html) for more information.

The unit tests don't cover:

Expand Down
202 changes: 202 additions & 0 deletions api/register/api.go
@@ -0,0 +1,202 @@
package apiregister

import (
"encoding/json"
"regexp"
"strings"
"time"

cerrors "github.com/cloudtrust/common-service/errors"
kc "github.com/cloudtrust/keycloak-client"
"github.com/nyaruka/phonenumbers"
)

// User representation
type User struct {
Gender *string `json:"gender,omitempty"`
FirstName *string `json:"firstName,omitempty"`
LastName *string `json:"lastName,omitempty"`
EmailAddress *string `json:"emailAddress,omitempty"`
PhoneNumber *string `json:"phoneNumber,omitempty"`
BirthDate *string `json:"birthDate,omitempty"`
BirthLocation *string `json:"birthLocation,omitempty"`
IDDocumentType *string `json:"idDocumentType,omitempty"`
IDDocumentNumber *string `json:"idDocumentNumber,omitempty"`
IDDocumentExpiration *string `json:"idDocumentExpiration,omitempty"`
}

// DBUser struct
type DBUser struct {
UserID *string `json:"-"`
BirthLocation *string `json:"birth_location,omitempty"`
IDDocumentType *string `json:"id_document_typ,omitempty"`
IDDocumentNumber *string `json:"id_document_num,omitempty"`
IDDocumentExpiration *string `json:"id_document_exp,omitempty"`
}

// Parameter references
const (
prmUserGender = "user_gender"
prmUserFirstName = "user_firstName"
prmUserLastName = "user_lastName"
prmUserEmail = "user_emailAddress"
prmUserPhoneNumber = "user_phoneNumber"
prmUserBirthDate = "user_birthDate"
prmUserBirthLocation = "user_birthLocation"
prmUserIDDocumentType = "user_idDocType"
prmUserIDDocumentNumber = "user_idDocNumber"
prmUserIDDocumentExpiration = "user_idDocExpiration"

regExpNames = `^([\wàáâäçèéêëìíîïñòóôöùúûüß]+([ '-][\wàáâäçèéêëìíîïñòóôöùúûüß]+)*){1,50}$`
regExpFirstName = regExpNames
regExpLastName = regExpNames
regExpEmail = `^.+\@.+\..+$`
regExpBirthLocation = regExpNames
// Multiple values with digits and letters separated by a single separator (space, dash)
regExpIDDocumentNumber = `^([\w\d]+([ -][\w\d]+)*){1,50}$`

dateLayout = "02.01.2006"
)

var (
allowedGender = map[string]bool{"M": true, "F": true}
allowedDocumentType = map[string]bool{"Identity card": true, "Passport": true}
)

// UserFromJSON creates a User using its json representation
func UserFromJSON(jsonRep string) (User, error) {
var user User
dec := json.NewDecoder(strings.NewReader(jsonRep))
dec.DisallowUnknownFields()
err := dec.Decode(&user)
return user, err
}

// UserToJSON returns a json representation of a given User
func (u *User) UserToJSON() string {
var bytes, _ = json.Marshal(u)
return string(bytes)
}

// UpdateUserRepresentation converts a given User to a Keycloak UserRepresentation
func (u *User) UpdateUserRepresentation(kcUser *kc.UserRepresentation) {
var (
bFalse = false
attributes = make(map[string][]string)
)

if u.Gender != nil {
attributes["gender"] = []string{*u.Gender}
}
if u.PhoneNumber != nil {
attributes["phoneNumber"] = []string{*u.PhoneNumber}
attributes["phoneNumberVerified"] = []string{"false"}
}
if u.BirthDate != nil {
attributes["birthDate"] = []string{*u.BirthDate}
}

kcUser.Email = u.EmailAddress
kcUser.EmailVerified = &bFalse
kcUser.Enabled = &bFalse
kcUser.FirstName = u.FirstName
kcUser.LastName = u.LastName
kcUser.Attributes = &attributes
}

// Validate checks the validity of the given User
func (u *User) Validate() error {
var err = validateParameterIn(prmUserGender, u.Gender, allowedGender, true)
if err != nil {
return err
}
err = validateParameterRegExp(prmUserFirstName, u.FirstName, regExpFirstName, true)
if err != nil {
return err
}
err = validateParameterRegExp(prmUserLastName, u.LastName, regExpLastName, true)
if err != nil {
return err
}
err = validateParameterRegExp(prmUserEmail, u.EmailAddress, regExpEmail, true)
if err != nil {
return err
}
err = validateParameterPhoneNumber(prmUserPhoneNumber, u.PhoneNumber)
if err != nil {
return err
}
err = validateParameterDate(prmUserBirthDate, u.BirthDate, false)
if err != nil {
return err
}
err = validateParameterRegExp(prmUserBirthLocation, u.BirthLocation, regExpBirthLocation, false)
if err != nil {
return err
}
err = validateParameterIn(prmUserIDDocumentType, u.IDDocumentType, allowedDocumentType, false)
if err != nil {
return err
}
err = validateParameterRegExp(prmUserIDDocumentNumber, u.IDDocumentNumber, regExpIDDocumentNumber, false)
if err != nil {
return err
}
err = validateParameterDate(prmUserIDDocumentExpiration, u.IDDocumentExpiration, false)
if err != nil {
return err
}
return nil
}

func validateParameterIn(prmName string, value *string, allowedValues map[string]bool, mandatory bool) error {
if value == nil {
if mandatory {
return cerrors.CreateMissingParameterError(prmName)
}
} else {
if _, ok := allowedValues[*value]; !ok {
return cerrors.CreateBadRequestError(cerrors.MsgErrInvalidParam + "." + prmName)
}
}
return nil
}

func validateParameterRegExp(prmName string, value *string, regExp string, mandatory bool) error {
if value == nil {
if mandatory {
return cerrors.CreateMissingParameterError(prmName)
}
} else {
res, _ := regexp.MatchString(regExp, strings.ToLower(*value))
if !res {
return cerrors.CreateBadRequestError(cerrors.MsgErrInvalidParam + "." + prmName)
}
}
return nil
}

func validateParameterPhoneNumber(prmName string, value *string) error {
if value == nil {
return cerrors.CreateMissingParameterError(prmName)
}
var metadata, err = phonenumbers.Parse(*value, "CH")
if err != nil || !phonenumbers.IsPossibleNumber(metadata) {
return cerrors.CreateBadRequestError(cerrors.MsgErrInvalidParam + "." + prmName)
}
return nil
}

func validateParameterDate(prmName string, value *string, mandatory bool) error {
if value == nil {
if mandatory {
return cerrors.CreateMissingParameterError(prmName)
}
} else {
var _, err = time.Parse(dateLayout, *value)
if err != nil {
return cerrors.CreateBadRequestError(cerrors.MsgErrInvalidParam + "." + prmName)
}
}
return nil
}

0 comments on commit 4ebccc6

Please sign in to comment.