def test_farm(): if valid_restws_config: farm = farmOS.farmOS(FARMOS_HOSTNAME, FARMOS_RESTWS_USERNAME, FARMOS_RESTWS_PASSWORD) farm.authenticate() return farm if valid_oauth_config: farm = farmOS.farmOS(FARMOS_HOSTNAME, username=FARMOS_OAUTH_USERNAME, password=FARMOS_OAUTH_PASSWORD, client_id=FARMOS_OAUTH_CLIENT_ID, client_secret=FARMOS_OAUTH_CLIENT_SECRET) farm.authenticate() return farm
def test_farm(): if valid_oauth_config: farm = farmOS.farmOS( FARMOS_HOSTNAME, client_id=FARMOS_OAUTH_CLIENT_ID, client_secret=FARMOS_OAUTH_CLIENT_SECRET, ) farm.authorize(username=FARMOS_OAUTH_USERNAME, password=FARMOS_OAUTH_PASSWORD) return farm
def authorize_farm( *, db: Session = Depends(get_db), farm_url: str = Body(...), auth_params: FarmAuthorizationParams, ): """ Authorize a new farm. Complete the OAuth Authorization Flow. This endpoint is only used when authorizing a new farm, before creation. See /authorize-farm/{farm_id} for authorizing existing farms. """ logging.debug("Authorizing new farm: " + farm_url) token = get_oauth_token(farm_url, auth_params) # Check the token expiration time. if token is not None and 'expires_at' in token: # Create datetime objects for comparison. now = datetime.now() expiration_time = datetime.fromtimestamp(float(token['expires_at'])) # Calculate seconds until expiration. timedelta = expiration_time - now expires_in = timedelta.total_seconds() # Update the token expires_in value token['expires_in'] = expires_in client_id = settings.AGGREGATOR_OAUTH_CLIENT_ID client_secret = settings.AGGREGATOR_OAUTH_CLIENT_SECRET # Allow OAuth over http if settings.AGGREGATOR_OAUTH_INSECURE_TRANSPORT: os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' try: logging.debug("Testing OAuth token with farmOS client.") logging.debug(token.dict()) client = farmOS( hostname=farm_url, client_id=client_id, client_secret=client_secret, scope=auth_params.scope, token=token.dict(), ) info = client.info() return {'token': token, 'info': info} except Exception as e: logging.debug("Error testing OAuth token with farmOS client: ") logging.debug(e) raise HTTPException( status_code=400, detail="Could not authenticate with farmOS server.")
def get_farm_client(db_session, farm): client_id = settings.AGGREGATOR_OAUTH_CLIENT_ID client_secret = settings.AGGREGATOR_OAUTH_CLIENT_SECRET if farm.token is None: error = "No OAuth token. Farm must be Authorized before making requests." crud.farm.update_is_authorized(db_session, farm_id=farm.id, is_authorized=False, auth_error=error) raise ClientError(error) token = FarmTokenBase.from_orm(farm.token) if farm.scope is None: error = "No Scope. Farm must be Authorized before making requests." crud.farm.update_is_authorized(db_session, farm_id=farm.id, is_authorized=False, auth_error=error) raise ClientError(error) # Use the saved scope. scope = farm.scope token_updater = partial(_save_token, db_session=db_session, farm=farm) # Allow OAuth over http if settings.AGGREGATOR_OAUTH_INSECURE_TRANSPORT: os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' try: client = farmOS(hostname=build_farm_url(farm.url), client_id=client_id, client_secret=client_secret, scope=scope, token=token.dict(), token_updater=token_updater) crud.farm.update_last_accessed(db_session, farm_id=farm.id) crud.farm.update_is_authorized(db_session, farm_id=farm.id, is_authorized=True) except Exception as e: if settings.AGGREGATOR_ALERT_ALL_ERRORS: admin_alert_email( db_session=db_session, message="Cannot authenticate client with farmOS server id: " + str(farm.id) + " - " + repr(e) + str(e)) logging.error("Cannot authenticate client with farmOS server id: " + str(farm.id) + " - " + repr(e) + str(e)) crud.farm.update_is_authorized(db_session, farm_id=farm.id, is_authorized=False, auth_error=str(e)) raise ClientError(e) return client
def test_not_authenticated_exception_raised(): with pytest.raises(NotAuthenticatedError): farm = farmOS.farmOS('test.farmos.net', 'username', 'password') farm.info()
def test_invalid_login(): farm = farmOS.farmOS('test.farmos.net', 'username', 'password') success = farm.authenticate() assert success is False
def test_valid_login(): farm = farmOS.farmOS(**valid_credentials) success = farm.authenticate() assert success is True
def test_unauthorized_request(test_farm): with pytest.raises(HTTPError, match=r"403 *."): farm = farmOS(FARMOS_HOSTNAME) farm.log.get()
def test_invalid_scopet(): with pytest.raises(InvalidScopeError): farm = farmOS(FARMOS_HOSTNAME, scope="bad_scope") farm.authorize(FARMOS_OAUTH_USERNAME, FARMOS_OAUTH_PASSWORD, scope="bad_scope")
def test_invalid_client_secret(): with pytest.raises(InvalidClientError): farm = farmOS(FARMOS_HOSTNAME, client_id="farm", client_secret="bad_pass") farm.authorize(FARMOS_OAUTH_USERNAME, FARMOS_OAUTH_PASSWORD)
def test_invalid_login(): with pytest.raises(InvalidGrantError): farm = farmOS(FARMOS_HOSTNAME) farm.authorize("username", "password")
def get_farm_client(db, farm): client_id = settings.AGGREGATOR_OAUTH_CLIENT_ID client_secret = settings.AGGREGATOR_OAUTH_CLIENT_SECRET # Check if another thread has started making requests to this same farm. existing_client = client_state.get(farm.id, None) if existing_client is not None: # Wait for the thread to signal that it is done. existing_client.wait() # Reload farm to get the latest token. db.refresh(farm) if farm.token is None: error = "No OAuth token. Farm must be Authorized before making requests." crud.farm.update_is_authorized(db, farm_id=farm.id, is_authorized=False, auth_error=error) raise ClientError(error) token = FarmTokenBase.from_orm(farm.token) if farm.scope is None: error = "No Scope. Farm must be Authorized before making requests." crud.farm.update_is_authorized(db, farm_id=farm.id, is_authorized=False, auth_error=error) raise ClientError(error) # Use the saved scope. scope = farm.scope token_updater = partial(_save_token, db=db, farm=farm) # Allow OAuth over http if settings.AGGREGATOR_OAUTH_INSECURE_TRANSPORT: os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' # Create a new threading event to signal other threads # that we are currently making requests to this farm. refreshing = threading.Event() client_state[farm.id] = refreshing try: # Remember if we need to refresh. trigger_refresh = False # Calculate time until expiration. now = time.time() expires_at = token.expires_at expires_in = expires_at - now # Trigger refresh if token expires in the next 15 seconds. if expires_in - 15 <= 0: # Mark the token as expired. token.expires_at = time.time() # Trigger refresh. trigger_refresh = True client = farmOS(hostname=build_farm_url(farm.url), client_id=client_id, client_secret=client_secret, scope=scope, token=token.dict(), token_updater=token_updater) # Make an authenticated request to trigger automatic refresh. # It is important the refresh is triggered while the thread still has the lock. if trigger_refresh: client.info() crud.farm.update_last_accessed(db, farm_id=farm.id) crud.farm.update_is_authorized(db, farm_id=farm.id, is_authorized=True) except Exception as e: if settings.AGGREGATOR_ALERT_ALL_ERRORS: admin_alert_email( db=db, message="Cannot authenticate client with farmOS server id: " + str(farm.id) + " - " + repr(e) + str(e)) logging.error("Cannot authenticate client with farmOS server id: " + str(farm.id) + " - " + repr(e) + str(e)) crud.farm.update_is_authorized(db, farm_id=farm.id, is_authorized=False, auth_error=str(e)) raise ClientError(e) finally: # Notify other threads that we are done making requests. # Tokens will have refreshed by now, so other clients can continue. refreshing.set() # Remove the threading object from memory. client_state.pop(farm.id, None) return client
import farmOS hostname = 'localhost:8888/farm-7.x-1.1/' username = '******' password = '******' farm = farmOS.farmOS(hostname, username, password) success = farm.authenticate() # Get farm info info = farm.info() # Get all logs logs = farm.log.get() # Get harvest logs harvests = farm.log.get({'type': 'farm_harvest'}) # Get log number 37 log = farm.log.get(37) # Get all assets assets = farm.asset.get() # Get all animal assets animals = farm.log.get({'type': 'animal'}) # Get all areas areas = farm.area.get() # Get field areas fields = farm.area.get({'area_type': 'field'}) # Get all terms terms = farm.term.get()
def test_farm(): farm = farmOS.farmOS(**valid_credentials) farm.authenticate() return farm