// CreateApp creates a new app. // // Creating a new app is a process composed of the following steps: // // 1. Save the app in the database // 2. Create the git repository using the repository manager // 3. Provision the app using the provisioner func CreateApp(app *App, user *auth.User) error { teams, err := user.Teams() if err != nil { return err } if len(teams) == 0 { return NoTeamsError{} } platform, err := getPlatform(app.Platform) if err != nil { return err } if platform.Disabled && !user.IsAdmin() { return InvalidPlatformError{} } var plan *Plan if app.Plan.Name == "" { plan, err = DefaultPlan() } else { plan, err = findPlanByName(app.Plan.Name) } if err != nil { return err } if app.TeamOwner == "" { if len(teams) > 1 { return ManyTeamsError{} } app.TeamOwner = teams[0].Name } err = app.ValidateTeamOwner(user) if err != nil { return err } app.Plan = *plan err = app.SetPool() if err != nil { return err } app.Teams = []string{app.TeamOwner} app.Owner = user.Email err = app.validate() if err != nil { return err } actions := []*action.Action{ &reserveUserApp, &insertApp, &exportEnvironmentsAction, &createRepository, &provisionApp, &setAppIp, } pipeline := action.NewPipeline(actions...) err = pipeline.Execute(app, user) if err != nil { return &AppCreationError{app: app.Name, Err: err} } return nil }
func createUser(w http.ResponseWriter, r *http.Request) error { registrationEnabled, _ := config.GetBool("auth:user-registration") if !registrationEnabled { token := r.Header.Get("Authorization") t, err := app.AuthScheme.Auth(token) if err != nil { return createDisabledErr } user, err := t.User() if err != nil { return createDisabledErr } if !user.IsAdmin() { return createDisabledErr } } var u auth.User err := json.NewDecoder(r.Body).Decode(&u) if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()} } _, err = app.AuthScheme.Create(&u) if err != nil { return handleAuthError(err) } err = u.CreateOnGandalf() if err != nil { return err } rec.Log(u.Email, "create-user") w.WriteHeader(http.StatusCreated) return nil }
func (s *InstanceSuite) TestGetServiceinstancesByServicesAndTeamsUserAdmin(c *check.C) { u := auth.User{Email: "*****@*****.**"} err := u.Create() c.Assert(err, check.IsNil) defer s.conn.Users().Remove(bson.M{"email": u.Email}) team := auth.Team{Name: "admin", Users: []string{u.Email}} err = s.conn.Teams().Insert(team) c.Assert(err, check.IsNil) defer s.conn.Teams().RemoveId(team.Name) srvc := Service{Name: "mysql", Teams: []string{s.team.Name}, IsRestricted: true} err = s.conn.Services().Insert(&srvc) c.Assert(err, check.IsNil) defer s.conn.Services().RemoveId(srvc.Name) instance := ServiceInstance{ Name: "j4sql", ServiceName: srvc.Name, Teams: []string{s.team.Name}, Apps: []string{}, Units: []string{}, } err = s.conn.ServiceInstances().Insert(&instance) c.Assert(err, check.IsNil) defer s.conn.ServiceInstances().Remove(bson.M{"name": instance.Name}) instances, err := GetServiceInstancesByServicesAndTeams([]Service{srvc}, &u, "") c.Assert(err, check.IsNil) c.Assert(instances, check.DeepEquals, []ServiceInstance{instance}) }
func (s *S) TestCreateTokenRemoveOldTokens(c *gocheck.C) { config.Set("auth:max-simultaneous-sessions", 2) u := auth.User{Email: "*****@*****.**", Password: "******"} err := u.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Users().Remove(bson.M{"email": u.Email}) defer s.conn.Tokens().RemoveAll(bson.M{"useremail": u.Email}) t1, err := newUserToken(&u) c.Assert(err, gocheck.IsNil) t2 := t1 t2.Token += "aa" err = s.conn.Tokens().Insert(t1, t2) _, err = createToken(&u, "123456") c.Assert(err, gocheck.IsNil) ok := make(chan bool, 1) go func() { for { ct, err := s.conn.Tokens().Find(bson.M{"useremail": u.Email}).Count() c.Assert(err, gocheck.IsNil) if ct == 2 { ok <- true return } runtime.Gosched() } }() select { case <-ok: case <-time.After(2e9): c.Fatal("Did not remove old tokens after 2 seconds") } }
func (s *OAuthScheme) Create(user *auth.User) (*auth.User, error) { err := user.Create() if err != nil { return nil, err } return user, nil }
func (s *OAuthScheme) Remove(u *auth.User) error { err := deleteAllTokens(u.Email) if err != nil { return err } return u.Delete() }
func removeUserFromTeamInRepository(u *auth.User, team *auth.Team) error { teamApps, err := team.AllowedApps() if err != nil { return err } userApps, err := u.AllowedApps() if err != nil { return err } appsToRemove := make([]string, 0, len(teamApps)) for _, teamApp := range teamApps { found := false for _, userApp := range userApps { if userApp == teamApp { found = true break } } if !found { appsToRemove = append(appsToRemove, teamApp) } } manager := repository.Manager() for _, app := range appsToRemove { manager.RevokeAccess(app, u.Email) } return nil }
// List returns the list of apps that the given user has access to. // // If the user does not have access to any app, this function returns an empty // list and a nil error. // // The list can be filtered through the filter parameter. func List(u *auth.User, filter *Filter) ([]App, error) { var apps []App conn, err := db.Conn() if err != nil { return nil, err } defer conn.Close() query := filter.Query() if u == nil || u.IsAdmin() { if err = conn.Apps().Find(query).All(&apps); err != nil { return []App{}, err } return apps, nil } ts, err := u.Teams() if err != nil { return []App{}, err } teams := auth.GetTeamsNames(ts) query["teams"] = bson.M{"$in": teams} if err := conn.Apps().Find(query).All(&apps); err != nil { return []App{}, err } return apps, nil }
func syncRepositoryApps(user *auth.User, beforeApps []string, roleCache map[string]*permission.Role) error { err := user.Reload() if err != nil { return err } afterApps, err := deployableApps(user, roleCache) if err != nil { return err } afterMap := map[string]struct{}{} for _, a := range afterApps { afterMap[a] = struct{}{} } manager := repository.Manager() for _, a := range beforeApps { var err error if _, ok := afterMap[a]; !ok { err = manager.RevokeAccess(a, user.Email) } if err != nil { log.Errorf("error revoking gandalf access for app %s, user %s: %s", a, user.Email, err) } } for _, a := range afterApps { err := manager.GrantAccess(a, user.Email) if err != nil { log.Errorf("error granting gandalf access for app %s, user %s: %s", a, user.Email, err) } } return nil }
func (s *SAMLAuthScheme) Create(user *auth.User) (*auth.User, error) { user.Password = "" if err := user.Create(); err != nil { return nil, err } return user, nil }
func GetServiceInstancesByServicesAndTeams(services []Service, u *auth.User, appName string) ([]ServiceInstance, error) { var instances []ServiceInstance teams, err := u.Teams() if err != nil { return nil, err } if len(teams) == 0 { return nil, nil } conn, err := db.Conn() if err != nil { return nil, err } defer conn.Close() var teamNames []string if !u.IsAdmin() { teamNames = auth.GetTeamsNames(teams) } query := genericServiceInstancesFilter(services, teamNames) if appName != "" { query["apps"] = appName } err = conn.ServiceInstances().Find(query).All(&instances) return instances, err }
func createUser(w http.ResponseWriter, r *http.Request) error { var u auth.User err := json.NewDecoder(r.Body).Decode(&u) if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()} } if !validation.ValidateEmail(u.Email) { return &errors.HTTP{Code: http.StatusBadRequest, Message: emailError} } if !validation.ValidateLength(u.Password, passwordMinLen, passwordMaxLen) { return &errors.HTTP{Code: http.StatusBadRequest, Message: passwordError} } if _, err = auth.GetUserByEmail(u.Email); err == nil { return &errors.HTTP{Code: http.StatusConflict, Message: "This email is already registered"} } gURL := repository.ServerURL() c := gandalf.Client{Endpoint: gURL} if _, err := c.NewUser(u.Email, keyToMap(u.Keys)); err != nil { return fmt.Errorf("Failed to create user in the git server: %s", err) } u.Quota = quota.Unlimited if limit, err := config.GetInt("quota:apps-per-user"); err == nil && limit > -1 { u.Quota.Limit = limit } if err := u.Create(); err == nil { rec.Log(u.Email, "create-user") w.WriteHeader(http.StatusCreated) return nil } return err }
func removeUserFromTeamInGandalf(u *auth.User, team *auth.Team) error { gURL := repository.ServerURL() teamApps, err := team.AllowedApps() if err != nil { return err } userApps, err := u.AllowedApps() if err != nil { return err } appsToRemove := make([]string, 0, len(teamApps)) for _, teamApp := range teamApps { found := false for _, userApp := range userApps { if userApp == teamApp { found = true break } } if !found { appsToRemove = append(appsToRemove, teamApp) } } client := gandalf.Client{Endpoint: gURL} if err := client.RevokeAccess(appsToRemove, []string{u.Email}); err != nil { return fmt.Errorf("Failed to revoke access from git repositories: %s", err) } return nil }
func createApiUser(t auth.Token, user *auth.User) (*apiUser, error) { permissions, err := user.Permissions() if err != nil { return nil, err } permData := make([]rolePermissionData, len(permissions)) for i, p := range permissions { if !permission.Check(t, p.Scheme, p.Context) { return nil, nil } permData[i] = rolePermissionData{ Name: p.Scheme.FullName(), ContextType: string(p.Context.CtxType), ContextValue: p.Context.Value, } } roleData := make([]rolePermissionData, len(user.Roles)) for i, userRole := range user.Roles { r, err := permission.FindRole(userRole.Name) if err != nil { return nil, err } roleData[i] = rolePermissionData{ Name: userRole.Name, ContextType: string(r.ContextType), ContextValue: userRole.ContextValue, } } return &apiUser{ Email: user.Email, Roles: roleData, Permissions: permData, }, nil }
func (s *S) TestNativeCreateExistingEmail(c *gocheck.C) { existingUser := auth.User{Email: "*****@*****.**"} existingUser.Create() scheme := NativeScheme{} user := &auth.User{Email: "*****@*****.**", Password: "******"} _, err := scheme.Create(user) c.Assert(err, gocheck.Equals, ErrEmailRegistered) }
func (s *S) TestCreateTokenShouldValidateThePassword(c *gocheck.C) { u := auth.User{Email: "*****@*****.**", Password: "******"} err := u.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Users().Remove(bson.M{"email": u.Email}) _, err = createToken(&u, "123") c.Assert(err, gocheck.NotNil) }
func (s *S) TestCreateTokenShouldValidateThePassword(c *check.C) { u := auth.User{Email: "*****@*****.**", Password: "******"} _, err := nativeScheme.Create(&u) c.Assert(err, check.IsNil) defer u.Delete() _, err = createToken(&u, "123") c.Assert(err, check.NotNil) }
func removeKeyFromDatabase(key *auth.Key, u *auth.User) error { conn, err := db.Conn() if err != nil { return err } defer conn.Close() u.RemoveKey(*key) return conn.Users().Update(bson.M{"email": u.Email}, u) }
func (s *S) TestPasswordTokenUser(c *check.C) { u := auth.User{Email: "*****@*****.**", Password: "******"} err := u.Create() c.Assert(err, check.IsNil) defer u.Delete() t, err := createPasswordToken(&u) c.Assert(err, check.IsNil) u2, err := t.user() c.Assert(err, check.IsNil) c.Assert(*u2, check.DeepEquals, u) }
func createTokenForUser(user *auth.User, perm, contextType, contextValue string, c *check.C) auth.Token { token, err := nativeScheme.Login(map[string]string{"email": user.Email, "password": "******"}) c.Assert(err, check.IsNil) role, err := permission.NewRole("provisioner-docker-"+user.Email+perm, contextType, "") c.Assert(err, check.IsNil) err = role.AddPermissions(perm) c.Assert(err, check.IsNil) err = user.AddRole(role.Name, contextValue) c.Assert(err, check.IsNil) return token }
func (s *S) TestCreateTokenShouldSaveTheTokenInTheDatabase(c *check.C) { u := auth.User{Email: "*****@*****.**", Password: "******"} _, err := nativeScheme.Create(&u) c.Assert(err, check.IsNil) defer u.Delete() _, err = createToken(&u, "123456") c.Assert(err, check.IsNil) var result Token err = s.conn.Tokens().Find(bson.M{"useremail": u.Email}).One(&result) c.Assert(err, check.IsNil) c.Assert(result.Token, check.NotNil) }
func (s *S) TestCreateTokenShouldSaveTheTokenInTheDatabase(c *gocheck.C) { u := auth.User{Email: "*****@*****.**", Password: "******"} err := u.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Users().Remove(bson.M{"email": u.Email}) _, err = createToken(&u, "123456") c.Assert(err, gocheck.IsNil) var result Token err = s.conn.Tokens().Find(bson.M{"useremail": u.Email}).One(&result) c.Assert(err, gocheck.IsNil) c.Assert(result.Token, gocheck.NotNil) }
func (s *S) TestPasswordTokenUser(c *gocheck.C) { u := auth.User{Email: "*****@*****.**", Password: "******"} err := u.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Users().Remove(bson.M{"email": u.Email}) t, err := createPasswordToken(&u) c.Assert(err, gocheck.IsNil) u2, err := t.user() u2.Keys = u.Keys c.Assert(err, gocheck.IsNil) c.Assert(*u2, gocheck.DeepEquals, u) }
func (s *S) TestResetPasswordThirdToken(c *gocheck.C) { scheme := NativeScheme{} u := auth.User{Email: "*****@*****.**"} err := u.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Users().Remove(bson.M{"email": u.Email}) t, err := createPasswordToken(&u) c.Assert(err, gocheck.IsNil) defer s.conn.PasswordTokens().Remove(bson.M{"_id": t.Token}) u2 := auth.User{Email: "*****@*****.**"} err = scheme.ResetPassword(&u2, t.Token) c.Assert(err, gocheck.Equals, auth.ErrInvalidToken) }
func (s *S) TestCreateTokenUsesDefaultCostWhenHasCostIsUndefined(c *check.C) { err := config.Unset("auth:hash-cost") c.Assert(err, check.IsNil) defer config.Set("auth:hash-cost", bcrypt.MinCost) u := auth.User{Email: "*****@*****.**", Password: "******"} _, err = nativeScheme.Create(&u) c.Assert(err, check.IsNil) defer u.Delete() cost = 0 tokenExpire = 0 _, err = createToken(&u, "123456") c.Assert(err, check.IsNil) }
func getApp(name string, u *auth.User) (*app.App, error) { a, err := app.GetByName(name) if err != nil { return nil, &errors.HTTP{Code: http.StatusNotFound, Message: fmt.Sprintf("App %s not found.", name)} } if u == nil || u.IsAdmin() { return a, nil } if !auth.CheckUserAccess(a.Teams, u) { return a, &errors.HTTP{Code: http.StatusForbidden, Message: "User does not have access to this app"} } return a, nil }
func (s *S) TestCreateTokenUsesDefaultCostWhenHasCostIsUndefined(c *gocheck.C) { err := config.Unset("auth:hash-cost") c.Assert(err, gocheck.IsNil) defer config.Set("auth:hash-cost", bcrypt.MinCost) u := auth.User{Email: "*****@*****.**", Password: "******"} err = u.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Users().Remove(bson.M{"email": u.Email}) cost = 0 tokenExpire = 0 _, err = createToken(&u, "123456") c.Assert(err, gocheck.IsNil) }
func (s *S) TestResetPassword(c *check.C) { scheme := NativeScheme{} defer s.server.Reset() u := auth.User{Email: "*****@*****.**"} err := u.Create() c.Assert(err, check.IsNil) defer u.Delete() p := u.Password err = scheme.StartPasswordReset(&u) c.Assert(err, check.IsNil) err = tsurutest.WaitCondition(time.Second, func() bool { s.server.RLock() defer s.server.RUnlock() return len(s.server.MailBox) == 1 }) c.Assert(err, check.IsNil) var token passwordToken err = s.conn.PasswordTokens().Find(bson.M{"useremail": u.Email}).One(&token) c.Assert(err, check.IsNil) err = scheme.ResetPassword(&u, token.Token) c.Assert(err, check.IsNil) u2, _ := auth.GetUserByEmail(u.Email) c.Assert(u2.Password, check.Not(check.Equals), p) var m authtest.Mail err = tsurutest.WaitCondition(time.Second, func() bool { s.server.RLock() defer s.server.RUnlock() if len(s.server.MailBox) != 2 { return false } m = s.server.MailBox[1] return true }) c.Assert(err, check.IsNil) c.Assert(m.From, check.Equals, "root") c.Assert(m.To, check.DeepEquals, []string{u.Email}) var buf bytes.Buffer template, err := getEmailResetPasswordSucessfullyTemplate() c.Assert(err, check.IsNil) err = template.Execute(&buf, map[string]string{"email": u.Email, "password": ""}) c.Assert(err, check.IsNil) expected := strings.Replace(buf.String(), "\n", "\r\n", -1) + "\r\n" lines := strings.Split(string(m.Data), "\r\n") lines[len(lines)-4] = "" c.Assert(strings.Join(lines, "\r\n"), check.Equals, expected) err = s.conn.PasswordTokens().Find(bson.M{"useremail": u.Email}).One(&token) c.Assert(err, check.IsNil) c.Assert(token.Used, check.Equals, true) }
func addSuperRole(u *auth.User) error { defaultRoleName := "AllowAll" r, err := permission.FindRole(defaultRoleName) if err != nil { r, err = permission.NewRole(defaultRoleName, string(permission.CtxGlobal), "") if err != nil { return err } } err = r.AddPermissions("*") if err != nil { return err } return u.AddRole(defaultRoleName, "") }
func GetServicesByOwnerTeams(teamKind string, u *auth.User) ([]Service, error) { teams, err := u.Teams() if err != nil { return nil, err } conn, err := db.Conn() if err != nil { return nil, err } defer conn.Close() teamsNames := auth.GetTeamsNames(teams) q := bson.M{teamKind: bson.M{"$in": teamsNames}} var services []Service err = conn.Services().Find(q).All(&services) return services, err }