Commit 7cc1329e authored by Andrei Mihu's avatar Andrei Mihu
Browse files

Extend validation of Google tokens to account for different token payloads.

parent bbf50065
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ The format is based on [keep a changelog](http://keepachangelog.com) and this pr
- Config options to allow listening on IPv4/6 and a particular network interface.
- Authoritative match modules now allow a `match_join` callback that triggers when users have completed their join process.
- New stream API function to upsert a user presence.
- Extended validation of Google tokens to account for different token payloads.

### Changed
- Presence list in match join responses no longer contains the user's own presence. 
+89 −17
Original line number Diff line number Diff line
@@ -77,8 +77,8 @@ type GoogleProfile struct {
	Sub string `json:"sub"`
	Azp string `json:"azp"`
	Aud string `json:"aud"`
	Iat string `json:"iat"`
	Exp string `json:"exp"`
	Iat int64  `json:"iat"`
	Exp int64  `json:"exp"`
	// Fields available only if the user granted the "profile" and "email" OAuth scopes.
	Email         string `json:"email"`
	EmailVerified string `json:"email_verified"`
@@ -260,37 +260,109 @@ func (c *Client) CheckGoogleToken(idToken string) (*GoogleProfile, error) {
	}

	claims := token.Claims.(jwt.MapClaims)
	profile := GoogleProfile{
		Iss: claims["iss"].(string),
		Sub: claims["sub"].(string),
		Azp: claims["azp"].(string),
		Aud: claims["aud"].(string),
		Iat: claims["iat"].(string),
		Exp: claims["exp"].(string),
	profile := &GoogleProfile{}
	if v, ok := claims["iss"]; ok {
		if profile.Iss, ok = v.(string); !ok {
			return nil, errors.New("google id token iss field invalid")
		}
	} else {
		return nil, errors.New("google id token iss field missing")
	}
	if v, ok := claims["sub"]; ok {
		if profile.Sub, ok = v.(string); !ok {
			return nil, errors.New("google id token sub field invalid")
		}
	} else {
		return nil, errors.New("google id token sub field missing")
	}
	if v, ok := claims["azp"]; ok {
		if profile.Azp, ok = v.(string); !ok {
			return nil, errors.New("google id token azp field invalid")
		}
	} else {
		return nil, errors.New("google id token azp field missing")
	}
	if v, ok := claims["aud"]; ok {
		if profile.Aud, ok = v.(string); !ok {
			return nil, errors.New("google id token aud field invalid")
		}
	} else {
		return nil, errors.New("google id token aud field missing")
	}
	if v, ok := claims["iat"]; ok {
		switch v.(type) {
		case string:
			if vi, err := strconv.Atoi(v.(string)); err != nil {
				return nil, errors.New("google id token iat field invalid")
			} else {
				profile.Iat = int64(vi)
			}
		case float64:
			profile.Iat = int64(v.(float64))
		case int64:
			profile.Iat = v.(int64)
		default:
			return nil, errors.New("google id token iat field unknown")
		}
	}
	if v, ok := claims["exp"]; ok {
		switch v.(type) {
		case string:
			if vi, err := strconv.Atoi(v.(string)); err != nil {
				return nil, errors.New("google id token exp field invalid")
			} else {
				profile.Exp = int64(vi)
			}
		case float64:
			profile.Exp = int64(v.(float64))
		case int64:
			profile.Exp = v.(int64)
		default:
			return nil, errors.New("google id token exp field unknown")
		}
	}
	if v, ok := claims["email"]; ok {
		profile.Email = v.(string)
		if profile.Email, ok = v.(string); !ok {
			return nil, errors.New("google id token email field invalid")
		}
	}
	if v, ok := claims["email_verified"]; ok {
		profile.EmailVerified = v.(string)
		if profile.EmailVerified, ok = v.(string); !ok {
			return nil, errors.New("google id token email verified field invalid")
		}
	}
	if v, ok := claims["name"]; ok {
		profile.Name = v.(string)
		if profile.Name, ok = v.(string); !ok {
			return nil, errors.New("google id token name field invalid")
		}
	}
	if v, ok := claims["picture"]; ok {
		profile.Picture = v.(string)
		if profile.Picture, ok = v.(string); !ok {
			return nil, errors.New("google id token picture field invalid")
		}
	}
	if v, ok := claims["given_name"]; ok {
		profile.GivenName = v.(string)
		if profile.GivenName, ok = v.(string); !ok {
			return nil, errors.New("google id token given name field invalid")
		}
	}
	if v, ok := claims["family_name"]; ok {
		profile.FamilyName = v.(string)
		if profile.FamilyName, ok = v.(string); !ok {
			return nil, errors.New("google id token family name field invalid")
		}
	}
	if v, ok := claims["locale"]; ok {
		profile.Locale = v.(string)
		if profile.Locale, ok = v.(string); !ok {
			return nil, errors.New("google id token locale field invalid")
		}
	}

	return &profile, nil
	// Check token has not expired.
	if profile.Exp != 0 && profile.Exp < time.Now().UTC().Unix() {
		return nil, errors.New("google id token expired")
	}

	return profile, nil
}

// CheckGameCenterID checks to see validity of the GameCenter playerID