// Create handles POST func (ctl *AuthController) Create(c *models.Context) { accessTokenRequest := models.AccessTokenRequestType{} err := c.Fill(&accessTokenRequest) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("The post data is invalid: %v", err.Error()), http.StatusBadRequest, ) return } // Audience is the host that Persona authenticates the user for var audience string if c.Site.Domain != "" { audience = c.Site.Domain } else if c.Site.SubdomainKey == "root" { audience = conf.ConfigStrings[conf.MicrocosmDomain] } else { audience = fmt.Sprintf("%s.%s", c.Site.SubdomainKey, conf.ConfigStrings[conf.MicrocosmDomain]) } // Verify persona assertion personaRequest := models.PersonaRequestType{ Assertion: accessTokenRequest.Assertion, Audience: audience, } jsonData, err := json.Marshal(personaRequest) if err != nil { glog.Errorf("Could not marshal Persona req: %s", err.Error()) c.RespondWithErrorMessage( fmt.Sprintf("Bad persona request format: %v", err.Error()), http.StatusBadRequest, ) return } resp, err := http.Post( conf.ConfigStrings[conf.PersonaVerifierURL], "application/json", bytes.NewReader(jsonData), ) if err != nil { glog.Errorln(err.Error()) c.RespondWithErrorMessage( fmt.Sprintf("Persona verification error: %v", err.Error()), http.StatusInternalServerError, ) return } body, err := ioutil.ReadAll(resp.Body) if err != nil { glog.Errorf("Couldn't read Persona response: %s", err.Error()) c.RespondWithErrorMessage( fmt.Sprintf("Error unmarshalling persona response: %v", err.Error()), http.StatusInternalServerError, ) return } resp.Body.Close() var personaResponse = models.PersonaResponseType{} json.Unmarshal(body, &personaResponse) if personaResponse.Status != "okay" { // Split and decode the assertion to log the user's email address. var decoded bool if personaRequest.Assertion != "" { parts := strings.Split(personaRequest.Assertion, "~") moreParts := strings.Split(parts[0], ".") if len(moreParts) > 1 { data, err := base64.StdEncoding.DecodeString(moreParts[1] + "====") if err == nil { decoded = true glog.Errorf("Bad Persona response: %+v with decoded assertion: %+v", personaResponse, data) } } } if !decoded { glog.Errorf("Bad Persona response: %+v with assertion: %+v", personaResponse, personaRequest) } c.RespondWithErrorMessage( fmt.Sprintf("Persona login error: %v", personaResponse.Status), http.StatusInternalServerError, ) return } if personaResponse.Email == "" { glog.Errorf("No persona email address") c.RespondWithErrorMessage( "Persona error: no email address received", http.StatusInternalServerError, ) return } // Retrieve user details by email address user, status, err := models.GetUserByEmailAddress(personaResponse.Email) if status == http.StatusNotFound { // Check whether this email is a spammer before we attempt to create // an account if models.IsSpammer(personaResponse.Email) { glog.Errorf("Spammer: %s", personaResponse.Email) c.RespondWithErrorMessage("Spammer", http.StatusInternalServerError) return } user, status, err = models.CreateUserByEmailAddress(personaResponse.Email) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("Couldn't create user: %v", err.Error()), http.StatusInternalServerError, ) return } } else if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("Error retrieving user: %v", err.Error()), http.StatusInternalServerError, ) return } // Create a corresponding profile for this user profile, status, err := models.GetOrCreateProfile(c.Site, user) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("Failed to create profile with ID %d: %v", profile.ID, err.Error()), status, ) return } // Fetch API client details by secret client, err := models.RetrieveClientBySecret(accessTokenRequest.ClientSecret) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("Error processing client secret: %v", err.Error()), http.StatusInternalServerError, ) return } // Create and store access token tokenValue, err := h.RandString(128) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("Could not generate a random string: %v", err.Error()), http.StatusInternalServerError, ) return } m := models.AccessTokenType{} m.TokenValue = tokenValue m.UserID = user.ID m.ClientID = client.ClientID status, err = m.Insert() if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("Could not create an access token: %v", err.Error()), status, ) return } audit.Create( c.Site.ID, h.ItemTypes[h.ItemTypeAuth], profile.ID, profile.ID, time.Now(), c.IP, ) c.RespondWithData(tokenValue) }
// Create handles POST func (ctl *UsersController) Create(c *models.Context) { // Batch create users by email address ems := []models.UserType{} err := c.Fill(&ems) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("The post data is invalid: %v", err.Error()), http.StatusBadRequest, ) return } if !c.Auth.IsSiteOwner { c.RespondWithErrorMessage( "Only a site owner can batch create users", http.StatusForbidden, ) return } for _, m := range ems { status, err := m.Validate(false) if err != nil { c.RespondWithErrorDetail(err, status) return } } // We are good to go profiles := []models.ProfileType{} for _, m := range ems { // Retrieve user details by email address user, status, err := models.GetUserByEmailAddress(m.Email) if status == http.StatusNotFound { user, status, err = models.CreateUserByEmailAddress(m.Email) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("Couldn't create user: %v", err.Error()), http.StatusInternalServerError, ) return } audit.Create( c.Site.ID, h.ItemTypes[h.ItemTypeUser], user.ID, c.Auth.ProfileID, time.Now(), c.IP, ) } else if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("Error retrieving user: %v", err.Error()), http.StatusInternalServerError, ) return } // create a corresponding profile for this user profile, status, err := models.GetOrCreateProfile(c.Site, user) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("Failed to create profile with ID %d: %v", profile.ID, err.Error()), status, ) return } audit.Create( c.Site.ID, h.ItemTypes[h.ItemTypeProfile], profile.ID, c.Auth.ProfileID, time.Now(), c.IP, ) profiles = append(profiles, profile) } c.RespondWithData(profiles) }