Class: OpenID::Server::Signatory

Inherits:
Object
  • Object
show all
Defined in:
lib/openid/server.rb

Overview

I sign things.

I also check signatures.

All my state is encapsulated in a store, which means I’m not generally pickleable but I am easy to reconstruct.

Constant Summary collapse

@@_normal_key =

keys have a bogus server URL in them because the filestore really does expect that key to be a URL. This seems a little silly for the server store, since I expect there to be only one server URL.

"http://localhost/|normal"
@@_dumb_key =
"http://localhost/|dumb"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(store) ⇒ Signatory

Create a new Signatory. store is The back-end where my associations are stored.



1022
1023
1024
1025
1026
# File 'lib/openid/server.rb', line 1022

def initialize(store)
  Util.truthy_assert(store)
  @store = store
  @secret_lifetime = 14 * 24 * 60 * 60
end

Instance Attribute Details

#secret_lifetimeObject

The number of seconds a secret remains valid. Defaults to 14 days.



1001
1002
1003
# File 'lib/openid/server.rb', line 1001

def secret_lifetime
  @secret_lifetime
end

#storeObject

Returns the value of attribute store.



1018
1019
1020
# File 'lib/openid/server.rb', line 1018

def store
  @store
end

Class Method Details

._dumb_keyObject



1014
1015
1016
# File 'lib/openid/server.rb', line 1014

def self._dumb_key
  @@_dumb_key
end

._normal_keyObject



1010
1011
1012
# File 'lib/openid/server.rb', line 1010

def self._normal_key
  @@_normal_key
end

Instance Method Details

#create_association(dumb = true, assoc_type = "HMAC-SHA1") ⇒ Object

Make a new association.



1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
# File 'lib/openid/server.rb', line 1098

def create_association(dumb = true, assoc_type = "HMAC-SHA1")
  secret = CryptUtil.random_string(OpenID.get_secret_size(assoc_type))
  uniq = Util.to_base64(CryptUtil.random_string(4))
  handle = format("{%s}{%x}{%s}", assoc_type, Time.now.to_i, uniq)

  assoc = Association.from_expires_in(
    secret_lifetime, handle, secret, assoc_type
  )

  key = if dumb
    @@_dumb_key
  else
    @@_normal_key
  end

  @store.store_association(key, assoc)
  assoc
end

#get_association(assoc_handle, dumb, check_expiration = true) ⇒ Object

Get the association with the specified handle.

Raises:

  • (ArgumentError)


1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
# File 'lib/openid/server.rb', line 1118

def get_association(assoc_handle, dumb, check_expiration = true)
  # Hmm.  We've created an interface that deals almost entirely
  # with assoc_handles.  The only place outside the Signatory
  # that uses this (and thus the only place that ever sees
  # Association objects) is when creating a response to an
  # association request, as it must have the association's
  # secret.

  raise ArgumentError.new("assoc_handle must not be None") unless assoc_handle

  key = if dumb
    @@_dumb_key
  else
    @@_normal_key
  end

  assoc = @store.get_association(key, assoc_handle)
  if assoc and assoc.expires_in <= 0
    Util.log(format(
      "requested %sdumb key %s is expired (by %s seconds)",
      (!dumb) ? "not-" : "",
      assoc_handle,
      assoc.expires_in,
    ))
    if check_expiration
      @store.remove_association(key, assoc_handle)
      assoc = nil
    end
  end

  assoc
end

#invalidate(assoc_handle, dumb) ⇒ Object

Invalidates the association with the given handle.



1152
1153
1154
1155
1156
1157
1158
1159
1160
# File 'lib/openid/server.rb', line 1152

def invalidate(assoc_handle, dumb)
  key = if dumb
    @@_dumb_key
  else
    @@_normal_key
  end

  @store.remove_association(key, assoc_handle)
end

#sign(response) ⇒ Object

Sign a response.

I take an OpenIDResponse, create a signature for everything in its signed list, and return a new copy of the response object with that signature included.



1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
# File 'lib/openid/server.rb', line 1061

def sign(response)
  signed_response = response.copy
  assoc_handle = response.request.assoc_handle
  if assoc_handle
    # normal mode disabling expiration check because even if the
    # association is expired, we still need to know some
    # properties of the association so that we may preserve
    # those properties when creating the fallback association.
    assoc = get_association(assoc_handle, false, false)

    if !assoc or assoc.expires_in <= 0
      # fall back to dumb mode
      signed_response.fields.set_arg(
        OPENID_NS, "invalidate_handle", assoc_handle
      )
      assoc_type = assoc ? assoc.assoc_type : "HMAC-SHA1"
      if assoc and assoc.expires_in <= 0
        # now do the clean-up that the disabled checkExpiration
        # code didn't get to do.
        invalidate(assoc_handle, false)
      end
      assoc = create_association(true, assoc_type)
    end
  else
    # dumb mode.
    assoc = create_association(true)
  end

  begin
    signed_response.fields = assoc.sign_message(signed_response.fields)
  rescue KVFormError => e
    raise EncodingError, e
  end
  signed_response
end

#verify(assoc_handle, message) ⇒ Object

Verify that the signature for some data is valid.



1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
# File 'lib/openid/server.rb', line 1029

def verify(assoc_handle, message)
  assoc = get_association(assoc_handle, true)
  unless assoc
    Util.log(format(
      "failed to get assoc with handle %s to verify " +
                                 "message %s",
      assoc_handle,
      message,
    ))
    return false
  end

  begin
    valid = assoc.check_message_signature(message)
  rescue StandardError => e
    Util.log(format(
      "Error in verifying %s with %s: %s",
      message,
      assoc,
      e,
    ))
    return false
  end

  valid
end