moduleOidcclassClientclassRegistrarincludeActiveModel::Validations,AttrRequired,AttrOptionalclassRegistrationFailed<HttpError;endcattr_accessor:plural_uri_attributes,:metadata_attributessingular_uri_attributes=[:logo_uri,:client_uri,:policy_uri,:tos_uri,:jwks_uri,:sector_identifier_uri,:initiate_login_uri]singular_attributes=[:application_type,:client_name,:jwks,:subject_type,:id_token_signed_response_alg,:id_token_encrypted_response_alg,:id_token_encrypted_response_enc,:userinfo_signed_response_alg,:userinfo_encrypted_response_alg,:userinfo_encrypted_response_enc,:request_object_signing_alg,:request_object_encryption_alg,:request_object_encryption_enc,:token_endpoint_auth_method,:token_endpoint_auth_signing_alg,:default_max_age,:require_auth_time]+singular_uri_attributesself.plural_uri_attributes=[:redirect_uris,:request_uris]plural_attributes=[:response_types,:grant_types,:contacts,:default_acr_values,]+plural_uri_attributesself.metadata_attributes=singular_attributes+plural_attributesrequired_metadata_attributes=[:redirect_uris]attr_required:endpointattr_optional:initial_access_tokenattr_required(*required_metadata_attributes)attr_optional(*(metadata_attributes-required_metadata_attributes))validates(*required_attributes,presence: true)validates:sector_identifier_uri,presence: {if: :sector_identifier_required?}validates(*singular_uri_attributes,url: true,allow_nil: true)validate:validate_plural_uri_attributesvalidate:validate_contactsdefinitialize(endpoint,attributes={})self.endpoint=endpointself.initial_access_token=attributes[:initial_access_token]self.class.metadata_attributes.eachdo|_attr_|self.send"#{_attr_}=",attributes[_attr_]endenddefsector_identifierifvalid_uri?(sector_identifier_uri)URI.parse(sector_identifier_uri).hostelsehosts=redirect_uris.collectdo|redirect_uri|ifvalid_uri?(redirect_uri,nil)URI.parse(redirect_uri).hostelsenilendend.compact.uniqifhosts.size==1hosts.firstelsenilendendenddefas_json(options={})validate!self.class.metadata_attributes.inject({})do|hash,_attr_|value=self.send_attr_hash.merge!_attr_=>valueunlessvalue.nil?hashendenddefregister!handle_responsedohttp_client.postendpoint,to_json,'Content-Type'=>'application/json'endenddefread# TODO: Do we want this feature even if we don't have rotate secret nor update metadata support?enddefvalidate!valid?orraiseValidationFailed.new(self)endprivatedefsector_identifier_required?subject_type.to_s=='pairwise'&§or_identifier.blank?enddefvalid_uri?(uri,schemes=['http','https'])# NOTE: specify nil for schemes to allow any schemesURI::regexp(schemes).match(uri).present?enddefvalidate_contactsifcontactsinclude_invalid=contacts.any?do|contact|beginmail=Mail::Address.new(contact)mail.address!=contact||mail.domain.split(".").length<=1rescue:invalidendenderrors.add:contacts,'includes invalid email'ifinclude_invalidendenddefvalidate_plural_uri_attributesself.class.plural_uri_attributes.eachdo|_attr_|if(uris=self.send(_attr_))include_invalid=uris.any?do|uri|!valid_uri?(uri,nil)enderrors.add_attr_,'includes invalid URL'ifinclude_invalidendendenddefhttp_clientcaseinitial_access_tokenwhennilOidc.http_clientwhenRack::OAuth2::AccessToken::Bearerinitial_access_tokenelseRack::OAuth2::AccessToken::Bearer.new(access_token: initial_access_token)endenddefhandle_responseresponse=yieldcaseresponse.statuswhen200..201handle_success_responseresponseelsehandle_error_responseresponseendenddefhandle_success_response(response)credentials=response.body.with_indifferent_accessClient.new(identifier: credentials[:client_id],secret: credentials[:client_secret],expires_in: credentials[:expires_in])enddefhandle_error_response(response)raiseRegistrationFailed.new(response.status,'Client Registration Failed',response)endendendend