Class: Sigstore::OIDC::IdentityToken

Inherits:
Object
  • Object
show all
Defined in:
lib/sigstore/oidc.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(raw_token) ⇒ IdentityToken

Returns a new instance of IdentityToken.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/sigstore/oidc.rb', line 33

def initialize(raw_token)
  @raw_token = raw_token

  @unverified_claims = self.class.decode_jwt(raw_token)
  @iss = @unverified_claims["iss"]
  @nbf = @unverified_claims["nbf"]
  @exp = @unverified_claims["exp"]

  # fail early if this token isn't within its validity period
  raise Error::InvalidIdentityToken, "identity token is not within its validity period" unless in_validity_period?

  if (identity_claim = KNOWN_OIDC_ISSUERS[issuer])
    unless @unverified_claims[identity_claim]
      raise Error::InvalidIdentityToken, "identity token is missing required claim: #{identity_claim}"
    end

    @identity = @unverified_claims[identity_claim]
    # https://github.com/sigstore/fulcio/blob/8311f93c01ea5b068a86d37c4bb51573289bfd69/pkg/identity/github/principal.go#L92
    @identity = "https://github.com/#{@identity}" if issuer == "https://token.actions.githubusercontent.com"
  else
    @identity = @unverified_claims["sub"]
  end
end

Instance Attribute Details

#identityObject (readonly)

Returns the value of attribute identity.



31
32
33
# File 'lib/sigstore/oidc.rb', line 31

def identity
  @identity
end

#raw_tokenObject (readonly)

Returns the value of attribute raw_token.



31
32
33
# File 'lib/sigstore/oidc.rb', line 31

def raw_token
  @raw_token
end

Class Method Details

.decode_jwt(raw_token) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/sigstore/oidc.rb', line 61

def self.decode_jwt(raw_token)
  # These claims are required by OpenID Connect, so
  # we can strongly enforce their presence.
  # See: https://openid.net/specs/openid-connect-basic-1_0.html#IDToken
  required = %w[aud sub iat exp iss]
  audience = DEFAULT_AUDIENCE
  leeway = 5

  _header, payload, _signature =
    raw_token
    .split(".", 3)
    .tap do |parts|
      raise Error::InvalidIdentityToken, "identity token is not a JWT" unless parts.length == 3
    end.map! do |part| # rubocop:disable Style/MultilineBlockChain
      part.unpack1("m*")
    rescue ArgumentError
      raise Error::InvalidIdentityToken, "Invalid base64 in identity token"
    end

  begin
    payload = JSON.parse(payload)
  rescue JSON::ParserError
    raise Error::InvalidIdentityToken, "Invalid JSON in identity token"
  end
  unless payload.is_a?(Hash)
    raise Error::InvalidIdentityToken,
          "Invalid JSON in identity token: must be a json object"
  end
  time = Time.now.to_i
  validate_required_claims(payload, required)
  validate_iat(payload["iat"], time, leeway)
  validate_nbf(payload["nbf"], time, leeway)
  validate_exp(payload["exp"], time, leeway)
  validate_aud(payload["aud"], audience)

  payload
end

Instance Method Details

#issuerObject



57
58
59
# File 'lib/sigstore/oidc.rb', line 57

def issuer
  @iss
end