Class: OpenID::Store::Filesystem

### Home Classes Methods

### In Files

- lib/openid/store/filesystem.rb

### Parent

Interface

### Methods

- ::new
- #_get_association
- #cleanup
- #cleanup_associations
- #cleanup_nonces
- #ensure_dir
- #filename_escape
- #get_association
- #get_association_filename
- #mktemp
- #remove_association
- #remove_if_present
- #safe64
- #store_association
- #use_nonce

### Files

- LICENSE

### Class/Module Index

Quicksearch

- OpenID
- OpenID::AX
- OpenID::AX::AXMessage
- OpenID::AX::AttrInfo
- OpenID::AX::Error
- OpenID::AX::FetchRequest
- OpenID::AX::FetchResponse
- OpenID::AX::KeyValueMessage
- OpenID::AX::StoreRequest
- OpenID::AX::StoreResponse
- OpenID::AssertionError
- OpenID::Association
- OpenID::AssociationNegotiator
- OpenID::Consumer
- OpenID::Consumer::AssociationManager
- OpenID::Consumer::CancelResponse
- OpenID::Consumer::CheckIDRequest
- OpenID::Consumer::DiffieHellmanSHA1Session
- OpenID::Consumer::DiffieHellmanSHA256Session
- OpenID::Consumer::DiffieHellmanSession
- OpenID::Consumer::DiscoveredServices
- OpenID::Consumer::DiscoveryManager
- OpenID::Consumer::FailureResponse
- OpenID::Consumer::IdResHandler
- OpenID::Consumer::NoEncryptionSession
- OpenID::Consumer::Response
- OpenID::Consumer::Session
- OpenID::Consumer::SetupNeededResponse
- OpenID::Consumer::SuccessResponse
- OpenID::CryptUtil
- OpenID::DiffieHellman
- OpenID::DiscoveryFailure
- OpenID::Extension
- OpenID::FetchingError
- OpenID::HTTPRedirectLimitReached
- OpenID::HTTPResponse
- OpenID::HTTPStatusError
- OpenID::InvalidOpenIDNamespace
- OpenID::KVFormError
- OpenID::KVPostNetworkError
- OpenID::Message
- OpenID::Message::KeyNotFound
- OpenID::NamespaceAliasRegistrationError
- OpenID::NamespaceMap
- OpenID::Nonce
- OpenID::OAuth
- OpenID::OAuth::Request
- OpenID::OAuth::Response
- OpenID::OpenIDError
- OpenID::OpenIDServiceEndpoint
- OpenID::PAPE
- OpenID::PAPE::Request
- OpenID::PAPE::Response
- OpenID::ProtocolError
- OpenID::RealmVerificationRedirected
- OpenID::SReg
- OpenID::SReg::NamespaceError
- OpenID::SReg::Request
- OpenID::SReg::Response
- OpenID::SSLFetchingError
- OpenID::Server
- OpenID::Server::AlreadySigned
- OpenID::Server::AssociateRequest
- OpenID::Server::BaseServerSession
- OpenID::Server::CheckAuthRequest
- OpenID::Server::CheckIDRequest
- OpenID::Server::Decoder
- OpenID::Server::DiffieHellmanSHA1ServerSession
- OpenID::Server::DiffieHellmanSHA256ServerSession
- OpenID::Server::Encoder
- OpenID::Server::EncodingError
- OpenID::Server::MalformedReturnURL
- OpenID::Server::MalformedTrustRoot
- OpenID::Server::NoReturnToError
- OpenID::Server::OpenIDRequest
- OpenID::Server::OpenIDResponse
- OpenID::Server::PlainTextServerSession
- OpenID::Server::ProtocolError
- OpenID::Server::Server
- OpenID::Server::Signatory
- OpenID::Server::SigningEncoder
- OpenID::Server::UntrustedReturnURL
- OpenID::Server::VersionError
- OpenID::Server::WebResponse
- OpenID::ServerError
- OpenID::StandardFetcher
- OpenID::Store
- OpenID::Store::Filesystem
- OpenID::Store::Interface
- OpenID::Store::Memcache
- OpenID::Store::Memory
- OpenID::TrustRoot
- OpenID::TrustRoot::TrustRoot
- OpenID::TypeURIMismatch
- OpenID::UI
- OpenID::UI::Request
- OpenID::URINorm
- OpenID::UndefinedOpenIDNamespace
- OpenID::Util
- OpenID::Yadis
- OpenID::Yadis::BasicServiceEndpoint
- OpenID::Yadis::CompoundFilter
- OpenID::Yadis::DiscoveryResult
- OpenID::Yadis::TransformFilterMaker
- OpenID::Yadis::XRDSError
- OpenID::Yadis::XRDSFraud
- OpenID::Yadis::XRI
- OpenID::Yadis::XRI::ProxyResolver
- OpenID::Yadis::XRI::XRIHTTPError
- HMAC
- HMAC::Base
- HMAC::SHA1
- HMAC::SHA256
- HMAC::SHA384
- HMAC::SHA512
- Net
- Net::HTTP
- HTMLComment
- HTMLTag
- HTMLText
- HTMLToken
- HTMLTokenizer
- HTMLTokenizerError
- Object

No matching classes.

# OpenID::Store::Filesystem

### Public Class Methods

new(directory) click to toggle source

Create a Filesystem store instance, putting all data in `directory`.

    # File lib/openid/store/filesystem.rb, line 15
    def initialize(directory)
      @nonce_dir = File.join(directory, 'nonces')
      @association_dir = File.join(directory, 'associations')
      @temp_dir = File.join(directory, 'temp')

      self.ensure_dir(@nonce_dir)
      self.ensure_dir(@association_dir)
      self.ensure_dir(@temp_dir)
    end

### Public Instance Methods

_get_association(filename) click to toggle source

    # File lib/openid/store/filesystem.rb, line 99
    def _get_association(filename)
      begin
        assoc_file = File.open(filename, "r")
      rescue Errno::ENOENT
        return nil
      else
        begin
          assoc_s = assoc_file.read
        ensure
          assoc_file.close
        end

        begin
          association = Association.deserialize(assoc_s)
        rescue
          self.remove_if_present(filename)
          return nil
        end

        # clean up expired associations
        if association.expires_in == 0
          self.remove_if_present(filename)
          return nil
        else
          return association
        end
      end
    end

cleanup() click to toggle source

Remove expired entries from the database. This is potentially expensive, so only run when it is acceptable to take time.

    # File lib/openid/store/filesystem.rb, line 170
    def cleanup
      cleanup_associations
      cleanup_nonces
    end

cleanup_associations() click to toggle source

    # File lib/openid/store/filesystem.rb, line 175
    def cleanup_associations
      association_filenames = Dir[File.join(@association_dir, "*")]
      count = 0
      association_filenames.each do |af|
        begin
          f = File.open(af, 'r')
        rescue Errno::ENOENT
          next
        else
          begin
            assoc_s = f.read
          ensure
            f.close
          end
          begin
            association = OpenID::Association.deserialize(assoc_s)
          rescue StandardError
            self.remove_if_present(af)
            next
          else
            if association.expires_in == 0
              self.remove_if_present(af)
              count += 1
            end
          end
        end
      end
      return count
    end

cleanup_nonces() click to toggle source

    # File lib/openid/store/filesystem.rb, line 205
    def cleanup_nonces
      nonces = Dir[File.join(@nonce_dir, "*")]
      now = Time.now.to_i

      count = 0
      nonces.each do |filename|
        nonce = filename.split('/')[-1]
        timestamp = nonce.split('-', 2)[0].to_i(16)
        nonce_age = (timestamp - now).abs
        if nonce_age > Nonce.skew
          self.remove_if_present(filename)
          count += 1
        end
      end
      return count
    end

get_association(server_url, handle=nil) click to toggle source

Retrieve an association

    # File lib/openid/store/filesystem.rb, line 79
    def get_association(server_url, handle=nil)
      # the filename with empty handle is the prefix for the associations
      # for a given server url
      filename = get_association_filename(server_url, handle)
      if handle
        return _get_association(filename)
      end
      assoc_filenames = Dir.glob(filename.to_s + '*')

      assocs = assoc_filenames.collect do |f|
        _get_association(f)
      end

      assocs = assocs.find_all { |a| not a.nil? }
      assocs = assocs.sort_by { |a| a.issued }

      return nil if assocs.empty?
      return assocs[-1]
    end

get_association_filename(server_url, handle) click to toggle source

Create a unique filename for a given server url and handle. The filename that is returned will contain the domain name from the server URL for ease of human inspection of the data dir.

    # File lib/openid/store/filesystem.rb, line 28
    def get_association_filename(server_url, handle)
      unless server_url.index('://')
        raise ArgumentError, "Bad server URL: #{server_url}"
      end

      proto, rest = server_url.split('://', 2)
      domain = filename_escape(rest.split('/',2)[0])
      url_hash = safe64(server_url)
      if handle
        handle_hash = safe64(handle)
      else
        handle_hash = ''
      end
      filename = [proto,domain,url_hash,handle_hash].join('-')
      File.join(@association_dir, filename)
    end

remove_association(server_url, handle) click to toggle source

Remove an association if it exists, otherwise do nothing.

    # File lib/openid/store/filesystem.rb, line 129
    def remove_association(server_url, handle)
      assoc = get_association(server_url, handle)

      if assoc.nil?
        return false
      else
        filename = get_association_filename(server_url, handle)
        return self.remove_if_present(filename)
      end
    end

store_association(server_url, association) click to toggle source

Store an association in the assoc directory

    # File lib/openid/store/filesystem.rb, line 46
    def store_association(server_url, association)
      assoc_s = association.serialize
      filename = get_association_filename(server_url, association.handle)
      f, tmp = mktemp

      begin
        begin
          f.write(assoc_s)
          f.fsync
        ensure
          f.close
        end

        begin
          File.rename(tmp, filename)
        rescue Errno::EEXIST

          begin
            File.unlink(filename)
          rescue Errno::ENOENT
            # do nothing
          end

          File.rename(tmp, filename)
        end

      rescue
        self.remove_if_present(tmp)
        raise
      end
    end

use_nonce(server_url, timestamp, salt) click to toggle source

Return whether the nonce is valid

    # File lib/openid/store/filesystem.rb, line 141
    def use_nonce(server_url, timestamp, salt)
      return false if (timestamp - Time.now.to_i).abs > Nonce.skew

      if server_url and !server_url.empty?
        proto, rest = server_url.split('://',2)
      else
        proto, rest = '',''
      end
      raise "Bad server URL" unless proto && rest

      domain = filename_escape(rest.split('/',2)[0])
      url_hash = safe64(server_url)
      salt_hash = safe64(salt)

      nonce_fn = '%08x-%s-%s-%s-%s'%[timestamp, proto, domain, url_hash, salt_hash]

      filename = File.join(@nonce_dir, nonce_fn)

      begin
        fd = File.new(filename, File::CREAT | File::EXCL | File::WRONLY, 0200)
        fd.close
        return true
      rescue Errno::EEXIST
        return false
      end
    end

### Protected Instance Methods

ensure_dir(dir_name) click to toggle source

ensure that a path exists

    # File lib/openid/store/filesystem.rb, line 260
    def ensure_dir(dir_name)
      FileUtils::mkdir_p(dir_name)
    end

filename_escape(s) click to toggle source

create a safe filename from a url

    # File lib/openid/store/filesystem.rb, line 231
    def filename_escape(s)
      s = '' if s.nil?
      filename_chunks = s.each_char.flat_map {|c|
        @@FILENAME_ALLOWED.include?(c) ? c : c.bytes.map {|b|
          "_%02X" % b
        }
      }.join
    end

mktemp() click to toggle source

Create a temporary file and return the File object and filename.

    # File lib/openid/store/filesystem.rb, line 225
    def mktemp
      f = Tempfile.new('tmp', @temp_dir)
      [f, f.path]
    end

remove_if_present(filename) click to toggle source

remove file if present in filesystem

    # File lib/openid/store/filesystem.rb, line 250
    def remove_if_present(filename)
      begin
        File.unlink(filename)
      rescue Errno::ENOENT
        return false
      end
      return true
    end

safe64(s) click to toggle source

    # File lib/openid/store/filesystem.rb, line 240
    def safe64(s)
      s = OpenID::CryptUtil.sha1(s)
      s = OpenID::Util.to_base64(s)
      s.gsub!('+', '_')
      s.gsub!('/', '.')
      s.gsub!('=', '')
      return s
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.