def test_admin_auth_services_post_create(self): with self.request_context_with_admin("/", method="POST"): flask.request.form = MultiDict([ ("name", "oauth"), ("protocol", "Google OAuth"), ("url", "http://url2"), ("username", "username"), ("password", "password"), ( "libraries", json.dumps([{ "short_name": self._default_library.short_name, "domains": ["nypl.org", "gmail.com"], }]), ), ]) response = (self.manager.admin_auth_services_controller. process_admin_auth_services()) assert response.status_code == 201 # The auth service was created and configured properly. auth_service = ExternalIntegration.admin_authentication(self._db) assert auth_service.protocol == response.get_data(as_text=True) assert "oauth" == auth_service.name assert "http://url2" == auth_service.url assert "username" == auth_service.username assert "password" == auth_service.password assert [self._default_library] == auth_service.libraries setting = ConfigurationSetting.for_library_and_externalintegration( self._db, "domains", self._default_library, auth_service) assert "domains" == setting.key assert ["nypl.org", "gmail.com"] == json.loads(setting.value)
def process_post(self): protocol = flask.request.form.get("protocol") id = flask.request.form.get("id") auth_service = ExternalIntegration.admin_authentication(self._db) fields = {"protocol": protocol, "id": id, "auth_service": auth_service} error = self.validate_form_fields(**fields) if error: return error is_new = False if not auth_service: if protocol: auth_service, is_new = get_one_or_create( self._db, ExternalIntegration, protocol=protocol, goal=ExternalIntegration.ADMIN_AUTH_GOAL, ) else: return NO_PROTOCOL_FOR_NEW_SERVICE name = flask.request.form.get("name") auth_service.name = name [protocol] = [p for p in self.protocols if p.get("name") == protocol] result = self._set_integration_settings_and_libraries(auth_service, protocol) if isinstance(result, ProblemDetail): return result if is_new: return Response(str(auth_service.protocol), 201) else: return Response(str(auth_service.protocol), 200)
def test_admin_auth_services_post_create(self): with self.request_context_with_admin("/", method="POST"): flask.request.form = MultiDict([ ("name", "oauth"), ("protocol", "Google OAuth"), ("url", "http://url2"), ("username", "username"), ("password", "password"), ("libraries", json.dumps([{ "short_name": self._default_library.short_name, "domains": ["nypl.org", "gmail.com"] }])), ]) response = self.manager.admin_auth_services_controller.process_admin_auth_services( ) eq_(response.status_code, 201) # The auth service was created and configured properly. auth_service = ExternalIntegration.admin_authentication(self._db) eq_(auth_service.protocol, response.response[0]) eq_("oauth", auth_service.name) eq_("http://url2", auth_service.url) eq_("username", auth_service.username) eq_("password", auth_service.password) eq_([self._default_library], auth_service.libraries) setting = ConfigurationSetting.for_library_and_externalintegration( self._db, "domains", self._default_library, auth_service) eq_("domains", setting.key) eq_(["nypl.org", "gmail.com"], json.loads(setting.value))
def test_admin_auth_services_post_create(self): with self.request_context_with_admin("/", method="POST"): flask.request.form = MultiDict([ ("name", "oauth"), ("protocol", "Google OAuth"), ("url", "http://url2"), ("username", "username"), ("password", "password"), ("libraries", json.dumps([{ "short_name": self._default_library.short_name, "domains": ["nypl.org", "gmail.com"] }])), ]) response = self.manager.admin_auth_services_controller.process_admin_auth_services() eq_(response.status_code, 201) # The auth service was created and configured properly. auth_service = ExternalIntegration.admin_authentication(self._db) eq_(auth_service.protocol, response.response[0]) eq_("oauth", auth_service.name) eq_("http://url2", auth_service.url) eq_("username", auth_service.username) eq_("password", auth_service.password) eq_([self._default_library], auth_service.libraries) setting = ConfigurationSetting.for_library_and_externalintegration( self._db, "domains", self._default_library, auth_service ) eq_("domains", setting.key) eq_(["nypl.org", "gmail.com"], json.loads(setting.value))
def from_config(cls, _db): integration = ExternalIntegration.lookup( _db, ExternalIntegration.NYPL_SHADOWCAT, ExternalIntegration.METADATA_GOAL) if not integration.url: raise CannotLoadConfiguration('No url found for NYPL Shadowcat') return cls(integration.url)
def from_config(cls, _db): integration = ExternalIntegration.lookup( _db, ExternalIntegration.BIBBLIO, ExternalIntegration.METADATA_GOAL ) if not integration or not (integration.username and integration.password): raise CannotLoadConfiguration('Bibblio improperly configured') return cls(_db, integration.username, integration.password)
def from_config(cls, _db): integration = ExternalIntegration.lookup( _db, ExternalIntegration.NYPL_SHADOWCAT, ExternalIntegration.METADATA_GOAL ) if not integration.url: raise CannotLoadConfiguration('No url found for NYPL Shadowcat') return cls(integration.url)
def do_run(self, _db=None, cmd_args=None, output=sys.stdout): _db = _db or self._db args = self.parse_command_line(self._db, cmd_args=cmd_args) default_library = Library.default(_db) adobe_integration = ExternalIntegration.lookup( _db, ExternalIntegration.ADOBE_VENDOR_ID, ExternalIntegration.DRM_GOAL, library=default_library ) if not adobe_integration: output.write( "Could not find an Adobe Vendor ID integration for default library %s.\n" % default_library.short_name ) return setting = adobe_integration.setting( AuthdataUtility.OTHER_LIBRARIES_KEY ) other_libraries = setting.json_value chosen_website = args.website_url if not chosen_website: for website in other_libraries.keys(): self.explain(output, other_libraries, website) return if (not args.short_name and not args.secret): self.explain(output, other_libraries, chosen_website) return if not args.short_name or not args.secret: output.write("To configure a library you must provide both --short_name and --secret.\n") return # All three arguments are specified. Set or modify the library's # SCT configuration. if chosen_website in other_libraries: what = "change" else: what = "set" output.write( "About to %s the Short Client Token configuration for %s.\n" % ( what, chosen_website ) ) if chosen_website in other_libraries: output.write("Old configuration:\n") short_name, secret = other_libraries[chosen_website] self.explain(output, other_libraries, chosen_website) other_libraries[chosen_website] = [args.short_name, args.secret] output.write("New configuration:\n") self.explain(output, other_libraries, chosen_website) setting.value = json.dumps(other_libraries) self._db.commit()
def from_config(cls, _db, **kwargs): integration = ExternalIntegration.lookup( _db, ExternalIntegration.NYT, ExternalIntegration.METADATA_GOAL ) if not integration: message = "No ExternalIntegration found for the NYT." raise CannotLoadConfiguration(message) return cls(_db, api_key=integration.password, **kwargs)
def from_config(cls, _db, mirror, **kwargs): integration = ExternalIntegration.lookup( _db, ExternalIntegration.CONTENT_CAFE, ExternalIntegration.METADATA_GOAL) if not integration or not (integration.username and integration.password): raise CannotLoadConfiguration( 'Content Cafe not properly configured') return cls(_db, mirror, integration.username, integration.password, **kwargs)
def set_secret(self, _db, website_url, vendor_id, short_name, secret, output): # Look up a library by its url setting. library_setting = get_one( _db, ConfigurationSetting, key=Configuration.WEBSITE_URL, value=website_url, ) if not library_setting: available_urls = _db.query( ConfigurationSetting ).filter( ConfigurationSetting.key==Configuration.WEBSITE_URL ).filter( ConfigurationSetting.library!=None ) raise Exception( "Could not locate library with URL %s. Available URLs: %s" % (website_url, ",".join(x.value for x in available_urls)) ) library = library_setting.library integration = ExternalIntegration.lookup( _db, ExternalIntegration.OPDS_REGISTRATION, ExternalIntegration.DISCOVERY_GOAL, library=library ) if not integration: integration, ignore = create( _db, ExternalIntegration, protocol=ExternalIntegration.OPDS_REGISTRATION, goal=ExternalIntegration.DISCOVERY_GOAL ) library.integrations.append(integration) vendor_id_s = integration.setting(AuthdataUtility.VENDOR_ID_KEY) username_s = ConfigurationSetting.for_library_and_externalintegration( _db, ExternalIntegration.USERNAME, library, integration ) password_s = ConfigurationSetting.for_library_and_externalintegration( _db, ExternalIntegration.PASSWORD, library, integration ) if vendor_id and short_name and secret: vendor_id_s.value = vendor_id username_s.value = short_name password_s.value = secret output.write( "Current Short Client Token configuration for %s:\n" % website_url ) output.write(" Vendor ID: %s\n" % vendor_id_s.value) output.write(" Library name: %s\n" % username_s.value) output.write(" Shared secret: %s\n" % password_s.value)
def from_config(cls, _db, **kwargs): """Create a ContentCafeAPI object based on database configuration. """ integration = ExternalIntegration.lookup( _db, ExternalIntegration.CONTENT_CAFE, ExternalIntegration.METADATA_GOAL) if not integration or not (integration.username and integration.password): raise CannotLoadConfiguration( 'Content Cafe not properly configured') return cls(_db, integration.username, integration.password, **kwargs)
def for_library(cls, library): """Find the appropriate CustomPatronCatalog for the given library.""" _db = Session.object_session(library) integration = ExternalIntegration.one_for_library_and_goal( _db, library, cls.GOAL) if not integration: return None protocol = integration.protocol if not protocol in cls.BY_PROTOCOL: raise CannotLoadConfiguration( "Unregistered custom patron catalog protocol: %s" % protocol) view_class = cls.BY_PROTOCOL[protocol] return view_class(library, integration)
def values(cls, library): _db = Session.object_session(library) integration = ExternalIntegration.lookup( _db, ExternalIntegration.NOVELIST, ExternalIntegration.METADATA_GOAL, library=library) if not integration: return (None, None) profile = integration.username password = integration.password return (profile, password)
def values(cls, library): _db = Session.object_session(library) integration = ExternalIntegration.lookup( _db, ExternalIntegration.NOVELIST, ExternalIntegration.METADATA_GOAL, library=library ) if not integration: return (None, None) profile = integration.username password = integration.password return (profile, password)
def from_config(cls, _db, **kwargs): """Create a ContentCafeAPI object based on database configuration. """ integration = ExternalIntegration.lookup( _db, ExternalIntegration.CONTENT_CAFE, ExternalIntegration.METADATA_GOAL ) if not integration or not (integration.username and integration.password): raise CannotLoadConfiguration('Content Cafe not properly configured') return cls( _db, integration.username, integration.password, **kwargs )
def for_library(cls, library): """Find the appropriate CustomPatronCatalog for the given library.""" _db = Session.object_session(library) integration = ExternalIntegration.one_for_library_and_goal( _db, library, cls.GOAL ) if not integration: return None protocol = integration.protocol if not protocol in cls.BY_PROTOCOL: raise CannotLoadConfiguration( "Unregistered custom patron catalog protocol: %s" % protocol ) view_class = cls.BY_PROTOCOL[protocol] return view_class(library, integration)
def for_protocol_goal_and_url(cls, _db, protocol, goal, url): """Get a LibraryRegistry for the given protocol, goal, and URL. Create the corresponding ExternalIntegration if necessary. """ try: integration = ExternalIntegration.with_setting_value( _db, protocol, goal, ExternalIntegration.URL, url).one() except NoResultFound: integration = None if not integration: integration, is_new = create(_db, ExternalIntegration, protocol=protocol, goal=goal) integration.setting(ExternalIntegration.URL).value = url return cls(integration)
def for_protocol_goal_and_url(cls, _db, protocol, goal, url): """Get a LibraryRegistry for the given protocol, goal, and URL. Create the corresponding ExternalIntegration if necessary. """ try: integration = ExternalIntegration.with_setting_value( _db, protocol, goal, ExternalIntegration.URL, url ).one() except NoResultFound: integration = None if not integration: integration, is_new = create( _db, ExternalIntegration, protocol=protocol, goal=goal ) integration.setting(ExternalIntegration.URL).value = url return cls(integration)
def check_storage_protocol(self, service): """For MARC Export integrations, check that the storage protocol corresponds to an existing storage integration.""" if service.protocol == MARCExporter.NAME: storage_protocol = service.setting(MARCExporter.STORAGE_PROTOCOL).value _db = Session.object_session(service) integration = ExternalIntegration.lookup( _db, storage_protocol, ExternalIntegration.STORAGE_GOAL) if not integration: return MISSING_SERVICE.detailed(_( "You set the storage protocol to %(protocol)s, but no storage service with that protocol is configured.", protocol=storage_protocol, )) if storage_protocol == ExternalIntegration.S3: # For S3, the storage service must also have a MARC file bucket. bucket = integration.setting(S3Uploader.MARC_BUCKET_KEY).value if not bucket: return MISSING_SERVICE.detailed(_( "You set the storage protocol to %(protocol)s, but the storage service with that protocol does not have a MARC file bucket configured.", protocol=storage_protocol, ))
try: Configuration.load() library = Library.default(_db) if not library: library, ignore = create( _db, Library, name=u'default', short_name=u'default', uuid=unicode(uuid.uuid4()) ) library.is_default = True # Create the Bibblio integration. bibblio_conf = Configuration.integration('Bibblio') if bibblio_conf: bibblio = EI( name=EI.BIBBLIO, protocol=EI.BIBBLIO, goal=EI.METADATA_GOAL ) _db.add(bibblio) bibblio.username = bibblio_conf.get('client_id') bibblio.password = bibblio_conf.get('client_secret') log_import(bibblio) # Create the Metadata Wrangler configuration. metadata_wrangler_conf = Configuration.integration('Metadata Wrangler') if metadata_wrangler_conf: wrangler = EI( name=EI.METADATA_WRANGLER, protocol=EI.METADATA_WRANGLER, goal=EI.METADATA_GOAL )
def from_config(cls, library, _db=None): """Initialize an AuthdataUtility from site configuration. :return: An AuthdataUtility if one is configured; otherwise None. :raise CannotLoadConfiguration: If an AuthdataUtility is incompletely configured. """ _db = _db or Session.object_session(library) if not _db: raise ValueError( "No database connection provided and could not derive one from Library object!" ) # Use a version of the library library = _db.merge(library, load=False) # Try to find an external integration with a configured Vendor ID. integrations = _db.query(ExternalIntegration).outerjoin( ExternalIntegration.libraries).filter( ExternalIntegration.protocol == ExternalIntegration.OPDS_REGISTRATION, ExternalIntegration.goal == ExternalIntegration.DISCOVERY_GOAL, Library.id == library.id) integration = None for possible_integration in integrations: vendor_id = ConfigurationSetting.for_externalintegration( cls.VENDOR_ID_KEY, possible_integration).value if vendor_id: integration = possible_integration break library_uri = ConfigurationSetting.for_library( Configuration.WEBSITE_URL, library).value if not integration: return None vendor_id = integration.setting(cls.VENDOR_ID_KEY).value library_short_name = ConfigurationSetting.for_library_and_externalintegration( _db, ExternalIntegration.USERNAME, library, integration).value secret = ConfigurationSetting.for_library_and_externalintegration( _db, ExternalIntegration.PASSWORD, library, integration).value other_libraries = None adobe_integration = ExternalIntegration.lookup( _db, ExternalIntegration.ADOBE_VENDOR_ID, ExternalIntegration.DRM_GOAL, library=library) if adobe_integration: other_libraries = adobe_integration.setting( cls.OTHER_LIBRARIES_KEY).json_value other_libraries = other_libraries or dict() if (not vendor_id or not library_uri or not library_short_name or not secret): raise CannotLoadConfiguration( "Short Client Token configuration is incomplete. " "vendor_id, username, password and " "Library website_url must all be defined.") if '|' in library_short_name: raise CannotLoadConfiguration( "Library short name cannot contain the pipe character.") return cls(vendor_id, library_uri, library_short_name, secret, other_libraries)
def external_integration(cls, _db): return ExternalIntegration.lookup( _db, ExternalIntegration.NYT, ExternalIntegration.METADATA_GOAL )
def from_config(cls, library: Library, _db=None): """Initialize an AuthdataUtility from site configuration. The library must be successfully registered with a discovery integration in order for that integration to be a candidate to provide configuration for the AuthdataUtility. :return: An AuthdataUtility if one is configured; otherwise None. :raise CannotLoadConfiguration: If an AuthdataUtility is incompletely configured. """ _db = _db or Session.object_session(library) if not _db: raise ValueError( "No database connection provided and could not derive one from Library object!" ) # Use a version of the library library = _db.merge(library, load=False) # Try to find an external integration with a configured Vendor ID. integrations = (_db.query(ExternalIntegration).outerjoin( ExternalIntegration.libraries).filter( ExternalIntegration.protocol == ExternalIntegration.OPDS_REGISTRATION, ExternalIntegration.goal == ExternalIntegration.DISCOVERY_GOAL, Library.id == library.id, )) for possible_integration in integrations: vendor_id = ConfigurationSetting.for_externalintegration( cls.VENDOR_ID_KEY, possible_integration).value registration_status = ( ConfigurationSetting.for_library_and_externalintegration( _db, RegistrationConstants.LIBRARY_REGISTRATION_STATUS, library, possible_integration, ).value) if (vendor_id and registration_status == RegistrationConstants.SUCCESS_STATUS): integration = possible_integration break else: return None library_uri = ConfigurationSetting.for_library( Configuration.WEBSITE_URL, library).value vendor_id = integration.setting(cls.VENDOR_ID_KEY).value library_short_name = ConfigurationSetting.for_library_and_externalintegration( _db, ExternalIntegration.USERNAME, library, integration).value secret = ConfigurationSetting.for_library_and_externalintegration( _db, ExternalIntegration.PASSWORD, library, integration).value other_libraries = None adobe_integration = ExternalIntegration.lookup( _db, ExternalIntegration.ADOBE_VENDOR_ID, ExternalIntegration.DRM_GOAL, library=library, ) if adobe_integration: other_libraries = adobe_integration.setting( cls.OTHER_LIBRARIES_KEY).json_value other_libraries = other_libraries or dict() if not vendor_id or not library_uri or not library_short_name or not secret: raise CannotLoadConfiguration( "Short Client Token configuration is incomplete. " "vendor_id (%s), username (%s), password (%s) and " "Library website_url (%s) must all be defined." % (vendor_id, library_uri, library_short_name, secret)) if "|" in library_short_name: raise CannotLoadConfiguration( "Library short name cannot contain the pipe character.") return cls(vendor_id, library_uri, library_short_name, secret, other_libraries)
def test_from_config(self): library = self._default_library library2 = self._library() self.initialize_adobe(library, [library2]) library_url = library.setting(Configuration.WEBSITE_URL).value library2_url = library2.setting(Configuration.WEBSITE_URL).value utility = AuthdataUtility.from_config(library) registry = ExternalIntegration.lookup( self._db, ExternalIntegration.OPDS_REGISTRATION, ExternalIntegration.DISCOVERY_GOAL, library=library ) eq_(library.short_name + "token", ConfigurationSetting.for_library_and_externalintegration( self._db, ExternalIntegration.USERNAME, library, registry).value) eq_(library.short_name + " token secret", ConfigurationSetting.for_library_and_externalintegration( self._db, ExternalIntegration.PASSWORD, library, registry).value) eq_(self.TEST_VENDOR_ID, utility.vendor_id) eq_(library_url, utility.library_uri) eq_( {library2_url : "%s token secret" % library2.short_name, library_url : "%s token secret" % library.short_name}, utility.secrets_by_library_uri ) eq_( {"%sTOKEN" % library.short_name.upper() : library_url, "%sTOKEN" % library2.short_name.upper() : library2_url }, utility.library_uris_by_short_name ) # If an integration is set up but incomplete, from_config # raises CannotLoadConfiguration. setting = ConfigurationSetting.for_library_and_externalintegration( self._db, ExternalIntegration.USERNAME, library, registry) old_short_name = setting.value setting.value = None assert_raises( CannotLoadConfiguration, AuthdataUtility.from_config, library ) setting.value = old_short_name setting = library.setting(Configuration.WEBSITE_URL) old_value = setting.value setting.value = None assert_raises( CannotLoadConfiguration, AuthdataUtility.from_config, library ) setting.value = old_value setting = ConfigurationSetting.for_library_and_externalintegration( self._db, ExternalIntegration.PASSWORD, library, registry) old_secret = setting.value setting.value = None assert_raises( CannotLoadConfiguration, AuthdataUtility.from_config, library ) setting.value = old_secret # If other libraries are not configured, that's fine. We'll # only have a configuration for ourselves. self.adobe_vendor_id.set_setting( AuthdataUtility.OTHER_LIBRARIES_KEY, None ) authdata = AuthdataUtility.from_config(library) eq_({library_url : "%s token secret" % library.short_name}, authdata.secrets_by_library_uri) eq_({"%sTOKEN" % library.short_name.upper(): library_url}, authdata.library_uris_by_short_name) # Short library names are case-insensitive. If the # configuration has the same library short name twice, you # can't create an AuthdataUtility. self.adobe_vendor_id.set_setting( AuthdataUtility.OTHER_LIBRARIES_KEY, json.dumps({ "http://a/" : ("a", "secret1"), "http://b/" : ("A", "secret2"), }) ) assert_raises(ValueError, AuthdataUtility.from_config, library) # If there is no Adobe Vendor ID integration set up, # from_config() returns None. self._db.delete(registry) eq_(None, AuthdataUtility.from_config(library))
LIBRARIES = _db.query(Library).all() # Import Circulation Manager base url. circ_manager_conf = Configuration.integration('Circulation Manager') if circ_manager_conf: url = circ_manager_conf.get('url') if url: setting = ConfigurationSetting.sitewide(_db, Configuration.BASE_URL_KEY) setting.value = unicode(url) log_import(setting) # Import Metadata Wrangler configuration. metadata_wrangler_conf = Configuration.integration('Metadata Wrangler') if metadata_wrangler_conf: integration = EI(protocol=EI.METADATA_WRANGLER, goal=EI.METADATA_GOAL) _db.add(integration) integration.url = metadata_wrangler_conf.get('url') integration.username = metadata_wrangler_conf.get('client_id') integration.password = metadata_wrangler_conf.get('client_secret') log_import(integration) # Import NoveList Select configuration. novelist = Configuration.integration('NoveList Select') if novelist: integration = EI(protocol=EI.NOVELIST, goal=EI.METADATA_GOAL) _db.add(integration) integration.username = novelist.get('profile')
def external_integration(cls, _db): return ExternalIntegration.lookup(_db, ExternalIntegration.NYT, ExternalIntegration.METADATA_GOAL)
log = logging.getLogger(name="Metadata Wrangler configuration import") def log_import(integration_or_setting): log.info("CREATED: %r" % integration_or_setting) _db = production_session() try: Configuration.load() shadowcat_conf = Configuration.integration('Shadowcat') if shadowcat_conf and shadowcat_conf.get('url'): shadowcat = EI( name=EI.NYPL_SHADOWCAT, protocol=EI.NYPL_SHADOWCAT, goal=EI.METADATA_GOAL ) _db.add(shadowcat) shadowcat.url = shadowcat_conf.get('url') log_import(shadowcat) content_cafe_conf = Configuration.integration('Content Cafe') if content_cafe_conf: content_cafe = EI( name=EI.CONTENT_CAFE, protocol=EI.CONTENT_CAFE, goal=EI.METADATA_GOAL ) _db.add(content_cafe)
log = logging.getLogger(name="Metadata Wrangler configuration import") def log_import(integration_or_setting): log.info("CREATED: %r" % integration_or_setting) _db = production_session() try: Configuration.load() shadowcat_conf = Configuration.integration('Shadowcat') if shadowcat_conf and shadowcat_conf.get('url'): shadowcat = EI(name=EI.NYPL_SHADOWCAT, protocol=EI.NYPL_SHADOWCAT, goal=EI.METADATA_GOAL) _db.add(shadowcat) shadowcat.url = shadowcat_conf.get('url') log_import(shadowcat) content_cafe_conf = Configuration.integration('Content Cafe') if content_cafe_conf: content_cafe = EI(name=EI.CONTENT_CAFE, protocol=EI.CONTENT_CAFE, goal=EI.METADATA_GOAL) _db.add(content_cafe) content_cafe.username = content_cafe_conf.get('username') content_cafe.password = content_cafe_conf.get('password')