本文整理汇总了Golang中github.com/openshift/origin/pkg/auth/api.NewDefaultUserIdentityInfo函数的典型用法代码示例。如果您正苦于以下问题:Golang NewDefaultUserIdentityInfo函数的具体用法?Golang NewDefaultUserIdentityInfo怎么用?Golang NewDefaultUserIdentityInfo使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了NewDefaultUserIdentityInfo函数的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Golang代码示例。
示例1: GetUserIdentity
// GetUserIdentity implements external/interfaces/Provider.GetUserIdentity
func (p *provider) GetUserIdentity(data *osincli.AccessData) (authapi.UserIdentityInfo, bool, error) {
userdata := githubUser{}
if _, err := getJSON(githubUserApiURL, data.AccessToken, &userdata); err != nil {
return nil, false, err
}
if userdata.ID == 0 {
return nil, false, errors.New("Could not retrieve GitHub id")
}
if len(p.allowedOrganizations) > 0 {
userOrgs, err := getUserOrgs(data.AccessToken)
if err != nil {
return nil, false, err
}
if !userOrgs.HasAny(p.allowedOrganizations.List()...) {
return nil, false, fmt.Errorf("User %s is not a member of any allowed organizations %v (user is a member of %v)", userdata.Login, p.allowedOrganizations.List(), userOrgs.List())
}
}
identity := authapi.NewDefaultUserIdentityInfo(p.providerName, fmt.Sprintf("%d", userdata.ID))
if len(userdata.Name) > 0 {
identity.Extra[authapi.IdentityDisplayNameKey] = userdata.Name
}
if len(userdata.Login) > 0 {
identity.Extra[authapi.IdentityPreferredUsernameKey] = userdata.Login
}
if len(userdata.Email) > 0 {
identity.Extra[authapi.IdentityEmailKey] = userdata.Email
}
glog.V(4).Infof("Got identity=%#v", identity)
return identity, true, nil
}
示例2: AuthenticatePassword
func (a *Authenticator) AuthenticatePassword(username, password string) (user.Info, bool, error) {
a.loadIfNeeded()
if len(username) > 255 {
username = username[:255]
}
if strings.Contains(username, ":") {
return nil, false, errors.New("Usernames may not contain : characters")
}
hash, ok := a.usernames[username]
if !ok {
return nil, false, nil
}
if ok, err := testPassword(password, hash); !ok || err != nil {
return nil, false, err
}
identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username)
user, err := a.mapper.UserFor(identity)
if err != nil {
return nil, false, fmt.Errorf("Error creating or updating mapping for: %#v due to %v", identity, err)
}
glog.V(4).Infof("Got userIdentityMapping: %#v", user)
return user, true, nil
}
示例3: AuthenticatePassword
func (a *Authenticator) AuthenticatePassword(username, password string) (user.Info, bool, error) {
areq := a.client.NewAccessRequest(osincli.PASSWORD, nil)
areq.CustomParameters["username"] = username
areq.CustomParameters["password"] = password
token, err := areq.GetToken()
if err != nil {
if oerr, ok := err.(*osincli.Error); ok {
if oerr.Id == osincli.E_ACCESS_DENIED {
return nil, false, nil
}
}
return nil, false, err
}
identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username)
identity.Extra["token"] = token.AccessToken
user, err := a.mapper.UserFor(identity)
if err != nil {
glog.V(4).Infof("Error creating or updating mapping for: %#v due to %v", identity, err)
return nil, false, err
}
glog.V(4).Infof("Got userIdentityMapping: %#v", user)
return user, true, nil
}
示例4: AuthenticateRequest
func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
id := headerValue(req.Header, a.config.IDHeaders)
if len(id) == 0 {
return nil, false, nil
}
identity := authapi.NewDefaultUserIdentityInfo(a.providerName, id)
if email := headerValue(req.Header, a.config.EmailHeaders); len(email) > 0 {
identity.Extra[authapi.IdentityEmailKey] = email
}
if name := headerValue(req.Header, a.config.NameHeaders); len(name) > 0 {
identity.Extra[authapi.IdentityDisplayNameKey] = name
}
if preferredUsername := headerValue(req.Header, a.config.PreferredUsernameHeaders); len(preferredUsername) > 0 {
identity.Extra[authapi.IdentityPreferredUsernameKey] = preferredUsername
}
user, err := a.mapper.UserFor(identity)
if err != nil {
glog.V(4).Infof("Error creating or updating mapping for: %#v due to %v", identity, err)
return nil, false, err
}
glog.V(4).Infof("Got userIdentityMapping: %#v", user)
return user, true, nil
}
示例5: AuthenticateRequest
func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
username := ""
for _, header := range a.config.UserNameHeaders {
header = strings.TrimSpace(header)
if len(header) == 0 {
continue
}
username = req.Header.Get(header)
if len(username) != 0 {
break
}
}
if len(username) == 0 {
return nil, false, nil
}
identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username)
user, err := a.mapper.UserFor(identity)
if err != nil {
return nil, false, err
}
glog.V(4).Infof("Got userIdentityMapping: %#v", user)
return user, true, nil
}
示例6: makeIdentityInfo
func makeIdentityInfo(providerName, providerUserName string, extra map[string]string) authapi.UserIdentityInfo {
info := authapi.NewDefaultUserIdentityInfo("idp", "bob")
if extra != nil {
info.Extra = extra
}
return info
}
示例7: AuthenticatePassword
// AuthenticatePassword approves any login attempt with non-blank username and password
func (a alwaysAcceptPasswordAuthenticator) AuthenticatePassword(username, password string) (user.Info, bool, error) {
if username == "" || password == "" {
return nil, false, nil
}
identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username)
user, err := a.identityMapper.UserFor(identity)
glog.V(4).Infof("Got userIdentityMapping: %#v", user)
if err != nil {
return nil, false, fmt.Errorf("Error creating or updating mapping for: %#v due to %v", identity, err)
}
return user, true, nil
}
示例8: AuthenticatePassword
// AuthenticatePassword approves any login attempt which is successfully validated with Keystone
func (a keystonePasswordAuthenticator) AuthenticatePassword(username, password string) (user.Info, bool, error) {
defer func() {
if e := recover(); e != nil {
utilruntime.HandleError(fmt.Errorf("Recovered panic: %v, %s", e, debug.Stack()))
}
}()
// if password is missing, fail authentication immediately
if len(password) == 0 {
return nil, false, nil
}
opts := gophercloud.AuthOptions{
IdentityEndpoint: a.url,
Username: username,
Password: password,
DomainName: a.domainName,
}
// Calling NewClient/Authenticate manually rather than simply calling AuthenticatedClient
// in order to pass in a transport object that supports SSL
client, err := openstack.NewClient(opts.IdentityEndpoint)
if err != nil {
glog.Warningf("Failed: Initializing openstack authentication client: %v", err)
return nil, false, err
}
client.HTTPClient = *a.client
err = openstack.AuthenticateV3(client, opts)
if err != nil {
if responseErr, ok := err.(*gophercloud.UnexpectedResponseCodeError); ok {
if responseErr.Actual == 401 {
return nil, false, nil
}
}
glog.Warningf("Failed: Calling openstack AuthenticateV3: %v", err)
return nil, false, err
}
identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username)
user, err := a.identityMapper.UserFor(identity)
if err != nil {
glog.V(4).Infof("Error creating or updating mapping for: %#v due to %v", identity, err)
return nil, false, err
}
glog.V(4).Infof("Got userIdentityMapping: %#v", user)
return user, true, nil
}
示例9: AuthenticatePassword
// AuthenticatePassword approves any login attempt with non-blank username and password
func (a alwaysAcceptPasswordAuthenticator) AuthenticatePassword(username, password string) (user.Info, bool, error) {
// Since this IDP doesn't validate usernames or passwords, disallow usernames consisting entirely of spaces
// Normalize usernames by removing leading/trailing spaces
username = strings.TrimSpace(username)
if username == "" || password == "" {
return nil, false, nil
}
identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username)
user, err := a.identityMapper.UserFor(identity)
if err != nil {
glog.V(4).Infof("Error creating or updating mapping for: %#v due to %v", identity, err)
return nil, false, err
}
glog.V(4).Infof("Got userIdentityMapping: %#v", user)
return user, true, nil
}
示例10: GetUserIdentity
// GetUserIdentity implements external/interfaces/Provider.GetUserIdentity
func (p *provider) GetUserIdentity(data *osincli.AccessData) (authapi.UserIdentityInfo, bool, error) {
req, _ := http.NewRequest("GET", p.userAPIURL, nil)
req.Header.Set("Authorization", fmt.Sprintf("bearer %s", data.AccessToken))
client := http.DefaultClient
if p.transport != nil {
client = &http.Client{Transport: p.transport}
}
res, err := client.Do(req)
if err != nil {
return nil, false, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, false, err
}
userdata := gitlabUser{}
err = json.Unmarshal(body, &userdata)
if err != nil {
return nil, false, err
}
if userdata.ID == 0 {
return nil, false, errors.New("Could not retrieve GitLab id")
}
identity := authapi.NewDefaultUserIdentityInfo(p.providerName, fmt.Sprintf("%d", userdata.ID))
if len(userdata.Name) > 0 {
identity.Extra[authapi.IdentityDisplayNameKey] = userdata.Name
}
if len(userdata.Username) > 0 {
identity.Extra[authapi.IdentityPreferredUsernameKey] = userdata.Username
}
if len(userdata.Email) > 0 {
identity.Extra[authapi.IdentityEmailKey] = userdata.Email
}
glog.V(4).Infof("Got identity=%#v", identity)
return identity, true, nil
}
示例11: IdentityFor
func (f *DefaultLDAPUserIdentityFactory) IdentityFor(user *ldap.Entry) (identity authapi.UserIdentityInfo, err error) {
uid := f.Definer.ID(user)
if uid == "" {
err = fmt.Errorf("Could not retrieve a non-empty value for ID attributes for dn=%q", user.DN)
return
}
id := authapi.NewDefaultUserIdentityInfo(f.ProviderName, uid)
// Add optional extra attributes if present
if name := f.Definer.Name(user); len(name) != 0 {
id.Extra[authapi.IdentityDisplayNameKey] = name
}
if email := f.Definer.Email(user); len(email) != 0 {
id.Extra[authapi.IdentityEmailKey] = email
}
if prefUser := f.Definer.PreferredUsername(user); len(prefUser) != 0 {
id.Extra[authapi.IdentityPreferredUsernameKey] = prefUser
}
identity = id
return
}
示例12: TestLookup
//.........这里部分代码省略.........
ExpectedActions: []test.Action{
{"GetIdentity", "idp:bob"},
{"GetUser", "bob"},
},
ExpectedError: true,
},
"existing identity, invalid user UID reference": {
ProviderName: "idp",
ProviderUserName: "bob",
ExistingIdentity: makeIdentity("bobIdentityUID", "idp", "bob", "bobUserUIDInvalid", "bob"),
ExistingUser: makeUser("bobUserUID", "bob", "idp:bob"),
ExpectedActions: []test.Action{
{"GetIdentity", "idp:bob"},
{"GetUser", "bob"},
},
ExpectedError: true,
},
"existing identity, user reference without identity backreference": {
ProviderName: "idp",
ProviderUserName: "bob",
ExistingIdentity: makeIdentity("bobIdentityUID", "idp", "bob", "bobUserUID", "bob"),
ExistingUser: makeUser("bobUserUID", "bob" /*, "idp:bob"*/),
ExpectedActions: []test.Action{
{"GetIdentity", "idp:bob"},
{"GetUser", "bob"},
},
ExpectedError: true,
},
"existing identity, user reference": {
ProviderName: "idp",
ProviderUserName: "bob",
ExistingIdentity: makeIdentity("bobIdentityUID", "idp", "bob", "bobUserUID", "bob"),
ExistingUser: makeUser("bobUserUID", "bob", "idp:bob"),
ExpectedActions: []test.Action{
{"GetIdentity", "idp:bob"},
{"GetUser", "bob"},
{"GetUser", "bob"}, // extra request is for group lookup
},
ExpectedUserName: "bob",
},
}
for k, tc := range testcases {
actions := []test.Action{}
identityRegistry := &test.IdentityRegistry{
Get: map[string]*api.Identity{},
Actions: &actions,
}
userRegistry := &test.UserRegistry{
Get: map[string]*api.User{},
Actions: &actions,
}
if tc.ExistingIdentity != nil {
identityRegistry.Get[tc.ExistingIdentity.Name] = tc.ExistingIdentity
}
if tc.ExistingUser != nil {
userRegistry.Get[tc.ExistingUser.Name] = tc.ExistingUser
}
mappingStorage := mappingregistry.NewREST(userRegistry, identityRegistry)
mappingRegistry := mappingregistry.NewRegistry(mappingStorage)
lookupMapper := &lookupIdentityMapper{
mappings: mappingRegistry,
users: userRegistry,
}
identity := authapi.NewDefaultUserIdentityInfo(tc.ProviderName, tc.ProviderUserName)
user, err := lookupMapper.UserFor(identity)
if tc.ExpectedError != (err != nil) {
t.Errorf("%s: Expected error=%v, got %v", k, tc.ExpectedError, err)
continue
}
if !tc.ExpectedError && user.GetName() != tc.ExpectedUserName {
t.Errorf("%s: Expected username %v, got %v", k, tc.ExpectedUserName, user.GetName())
continue
}
for i, action := range actions {
if len(tc.ExpectedActions) <= i {
t.Fatalf("%s: expected %d actions, got extras: %#v", k, len(tc.ExpectedActions), actions[i:])
continue
}
expectedAction := tc.ExpectedActions[i]
if !reflect.DeepEqual(expectedAction, action) {
t.Fatalf("%s: expected\n\t%s %#v\nGot\n\t%s %#v", k, expectedAction.Name, expectedAction.Object, action.Name, action.Object)
continue
}
}
if len(actions) < len(tc.ExpectedActions) {
t.Errorf("Missing %d additional actions:\n\t%#v", len(tc.ExpectedActions)-len(actions), tc.ExpectedActions[len(actions):])
}
}
}
示例13: getIdentity
//.........这里部分代码省略.........
return nil, false, err
}
defer l.Close()
// If specified, bind the username/password for search phase
if len(a.options.BindDN) > 0 {
if err := l.Bind(a.options.BindDN, a.options.BindPassword); err != nil {
return nil, false, err
}
}
// & together the filter specified in the LDAP options with the user-specific filter
filter := fmt.Sprintf("(&%s(%s=%s))",
a.options.URL.Filter,
ldap.EscapeFilter(a.options.URL.QueryAttribute),
ldap.EscapeFilter(username),
)
// Build list of attributes to retrieve
attrs := util.NewStringSet(a.options.URL.QueryAttribute)
attrs.Insert(a.options.AttributeEmail...)
attrs.Insert(a.options.AttributeName...)
attrs.Insert(a.options.AttributePreferredUsername...)
attrs.Insert(a.options.AttributeID...)
// Search for LDAP record
searchRequest := ldap.NewSearchRequest(
a.options.URL.BaseDN, // base dn
int(a.options.URL.Scope), // scope
ldap.NeverDerefAliases, // deref
2, // size limit, we want to know if this is not unique, but don't want the entire tree
0, // no client-specified time limit, determined by LDAP server. TODO: make configurable?
false, // not types only
filter, // filter
attrs.List(), // attributes to retrieve
nil, // controls
)
glog.V(4).Infof("searching for %s", filter)
results, err := l.Search(searchRequest)
if err != nil {
return nil, false, err
}
if len(results.Entries) == 0 {
// 0 results means a missing username, not an error
glog.V(4).Infof("no entries matching %s", filter)
return nil, false, nil
}
if len(results.Entries) > 1 {
// More than 1 result means a misconfigured server filter or query parameter
return nil, false, fmt.Errorf("multiple entries found matching %q", username)
}
entry := results.Entries[0]
glog.V(4).Infof("found dn=%q for %s", entry.DN, filter)
// Bind with given username and password to attempt to authenticate
if err := l.Bind(entry.DN, password); err != nil {
glog.V(4).Infof("error binding password for %q: %v", entry.DN, err)
if err, ok := err.(*ldap.Error); ok {
switch err.ResultCode {
case ldap.LDAPResultInappropriateAuthentication:
// inappropriateAuthentication (48)
// Indicates the server requires the client that had attempted
// to bind anonymously or without supplying credentials to
// provide some form of credentials.
fallthrough
case ldap.LDAPResultInvalidCredentials:
// invalidCredentials (49)
// Indicates that the provided credentials (e.g., the user's name
// and password) are invalid.
// Authentication failed, return false, but no error
return nil, false, nil
}
}
return nil, false, err
}
// Build the identity
uid := getAttributeValue(entry, a.options.AttributeID)
if uid == "" {
return nil, false, fmt.Errorf("Could not retrieve a non-empty value from %v attributes for dn=%q", a.options.AttributeID, entry.DN)
}
identity := authapi.NewDefaultUserIdentityInfo(a.providerName, uid)
// Add optional extra attributes if present
for k, attrs := range map[string][]string{
authapi.IdentityPreferredUsernameKey: a.options.AttributePreferredUsername,
authapi.IdentityEmailKey: a.options.AttributeEmail,
authapi.IdentityDisplayNameKey: a.options.AttributeName,
} {
if v := getAttributeValue(entry, attrs); len(v) != 0 {
identity.Extra[k] = v
}
}
return identity, true, nil
}
示例14: GetUserIdentity
// GetUserIdentity implements external/interfaces/Provider.GetUserIdentity
func (p provider) GetUserIdentity(data *osincli.AccessData) (authapi.UserIdentityInfo, bool, error) {
// Token response MUST include id_token
// http://openid.net/specs/openid-connect-core-1_0.html#TokenResponse
idToken, ok := data.ResponseData["id_token"].(string)
if !ok {
return nil, false, fmt.Errorf("No id_token returned in %v", data.ResponseData)
}
// id_token MUST be a valid JWT
idTokenClaims, err := decodeJWT(idToken)
if err != nil {
return nil, false, err
}
if p.IDTokenValidator != nil {
if err := p.IDTokenValidator(idTokenClaims); err != nil {
return nil, false, err
}
}
// TODO: validate JWT
// http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
// id_token MUST contain a sub claim as the subject identifier
// http://openid.net/specs/openid-connect-core-1_0.html#IDToken
idTokenSubject, ok := idTokenClaims[SubjectClaim].(string)
if !ok {
return nil, false, fmt.Errorf("id_token did not contain a 'sub' claim: %#v", idTokenClaims)
}
// Use id_token claims by default
claims := idTokenClaims
// If we have a userinfo URL, use it to get more detailed claims
if len(p.UserInfoURL) != 0 {
userInfoClaims, err := fetchUserInfo(p.UserInfoURL, data.AccessToken, p.transport)
if err != nil {
return nil, false, err
}
// The sub (subject) Claim MUST always be returned in the UserInfo Response.
// http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
userInfoSubject, ok := userInfoClaims[SubjectClaim].(string)
if !ok {
return nil, false, fmt.Errorf("userinfo response did not contain a 'sub' claim: %#v", userInfoClaims)
}
// The sub Claim in the UserInfo Response MUST be verified to exactly match the sub Claim in the ID Token;
// if they do not match, the UserInfo Response values MUST NOT be used.
// http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
if userInfoSubject != idTokenSubject {
return nil, false, fmt.Errorf("userinfo 'sub' claim (%s) did not match id_token 'sub' claim (%s)", userInfoSubject, idTokenSubject)
}
// Merge in userinfo claims in case id_token claims contained some that userinfo did not
for k, v := range userInfoClaims {
claims[k] = v
}
}
id, _ := getClaimValue(claims, p.IDClaims)
if id == "" {
return nil, false, fmt.Errorf("Could not retrieve id claim for %#v", p.IDClaims)
}
identity := authapi.NewDefaultUserIdentityInfo(p.providerName, id)
if preferredUsername, _ := getClaimValue(claims, p.PreferredUsernameClaims); len(preferredUsername) != 0 {
identity.Extra[authapi.IdentityPreferredUsernameKey] = preferredUsername
}
if email, _ := getClaimValue(claims, p.EmailClaims); len(email) != 0 {
identity.Extra[authapi.IdentityEmailKey] = email
}
if name, _ := getClaimValue(claims, p.NameClaims); len(name) != 0 {
identity.Extra[authapi.IdentityDisplayNameKey] = name
}
glog.V(4).Infof("identity=%v", identity)
return identity, true, nil
}
示例15: TestProvision
//.........这里部分代码省略.........
"existing identity, invalid user UID reference": {
ProviderName: "idp",
ProviderUserName: "bob",
ExistingIdentity: makeIdentity("bobIdentityUID", "idp", "bob", "bobUserUIDInvalid", "bob"),
ExistingUser: makeUser("bobUserUID", "bob", "idp:bob"),
NewIdentityGetterResponses: []interface{}{},
ExpectedActions: []test.Action{
{"GetIdentity", "idp:bob"},
{"GetUser", "bob"},
},
ExpectedError: true,
},
"existing identity, user reference without identity backreference": {
ProviderName: "idp",
ProviderUserName: "bob",
ExistingIdentity: makeIdentity("bobIdentityUID", "idp", "bob", "bobUserUID", "bob"),
ExistingUser: makeUser("bobUserUID", "bob" /*, "idp:bob"*/),
NewIdentityGetterResponses: []interface{}{},
ExpectedActions: []test.Action{
{"GetIdentity", "idp:bob"},
{"GetUser", "bob"},
},
ExpectedError: true,
},
"existing identity, user reference": {
ProviderName: "idp",
ProviderUserName: "bob",
ExistingIdentity: makeIdentity("bobIdentityUID", "idp", "bob", "bobUserUID", "bob"),
ExistingUser: makeUser("bobUserUID", "bob", "idp:bob"),
NewIdentityGetterResponses: []interface{}{},
ExpectedActions: []test.Action{
{"GetIdentity", "idp:bob"},
{"GetUser", "bob"},
},
ExpectedUserName: "bob",
},
}
for k, tc := range testcases {
actions := []test.Action{}
identityRegistry := &test.IdentityRegistry{
Get: map[string]*api.Identity{},
Actions: &actions,
}
userRegistry := &test.UserRegistry{
Get: map[string]*api.User{},
Actions: &actions,
}
if tc.ExistingIdentity != nil {
identityRegistry.Get[tc.ExistingIdentity.Name] = tc.ExistingIdentity
}
if tc.ExistingUser != nil {
userRegistry.Get[tc.ExistingUser.Name] = tc.ExistingUser
}
newIdentityUserGetter := &testNewIdentityGetter{responses: tc.NewIdentityGetterResponses}
provisionMapper := &provisioningIdentityMapper{
identity: identityRegistry,
user: userRegistry,
provisioningStrategy: newIdentityUserGetter,
}
identity := authapi.NewDefaultUserIdentityInfo(tc.ProviderName, tc.ProviderUserName)
user, err := provisionMapper.UserFor(identity)
if tc.ExpectedError != (err != nil) {
t.Errorf("%s: Expected error=%v, got %v", k, tc.ExpectedError, err)
continue
}
if !tc.ExpectedError && user.GetName() != tc.ExpectedUserName {
t.Errorf("%s: Expected username %v, got %v", k, tc.ExpectedUserName, user.GetName())
continue
}
if newIdentityUserGetter.called != len(tc.NewIdentityGetterResponses) {
t.Errorf("%s: Expected %d calls to UserForNewIdentity, got %d", k, len(tc.NewIdentityGetterResponses), newIdentityUserGetter.called)
}
for i, action := range actions {
if len(tc.ExpectedActions) <= i {
t.Fatalf("%s: expected %d actions, got extras: %#v", k, len(tc.ExpectedActions), actions[i:])
continue
}
expectedAction := tc.ExpectedActions[i]
if !reflect.DeepEqual(expectedAction, action) {
t.Fatalf("%s: expected\n\t%s %#v\nGot\n\t%s %#v", k, expectedAction.Name, expectedAction.Object, action.Name, action.Object)
continue
}
}
if len(actions) < len(tc.ExpectedActions) {
t.Errorf("Missing %d additional actions:\n\t%#v", len(tc.ExpectedActions)-len(actions), tc.ExpectedActions[len(actions):])
}
}
}