Commit 4c572f21 authored by Birin Sanchez's avatar Birin Sanchez
Browse files

* Remove all methods and modules used in old SSH VPN.



* Remove all SSH VPN configuration parameters.

* Remove all modules used by old subscription logic in Celery
  tasks.
Signed-off-by: Birin Sanchez's avatarBirin Sanchez <birin.sanchez@puri.sm>
parent df07e9eb
......@@ -43,10 +43,6 @@ WOO_UPGRADE_PAY_URL = http://wp.example.com/checkout/order-pay/{}/?pay_for_order
WOO_BUNDLES_INFO_FILE = /etc/opt/purist/middleware/upgrades_downgrades.yml
WOO_REG_OPTIONS_INFO_FILE = /etc/opt/purist/middleware/registration_options.yml
OVPN_HOSTNAME=ssh.example.com
OVPN_PORT=22
OVPN_USERNAME=username
OVPN_FILEPATH="/path/to/{IDENTITY}/{IDENTITY}.ovpn"
TUNNEL_HOST=https://example.com
PASSWORD_RESET_TOKEN_EXPIRES=1800
......
import paramiko
from celery.utils.log import get_task_logger
from django.conf import settings
from django.db import transaction
from django.utils import timezone
from woocommerce import API as WOO_API
from ..models import ExternalCredit, ExternalBundle, Limit
from ..models import ExternalCredit
from cart.models import ChosenReward
from ldapregister.models import LdapPerson
logger = get_task_logger(__name__)
def get_woo_connection():
return WOO_API(
url=settings.WOO_URL,
consumer_key=settings.WOO_CONSUMER_KEY,
consumer_secret=settings.WOO_CONSUMER_SECRET,
wp_api=settings.WOO_WP_API,
version=settings.WOO_VERSION,
query_string_auth=settings.WOO_QUERY_STRING_AUTH,
)
def get_username_from_woo_customer_id(customer_id, woo=None):
if woo is None:
woo = get_woo_connection()
try:
query = "customers/" + str(customer_id)
result = woo.get(query).json()
return result["username"]
except Exception as e:
logger.exception("Could not retrieve username for customer_id " + str(customer_id))
return "invalid"
return account
def get_openvpn_ssh_connection():
# make ssh connection to OpenVPN server
# (uses system host keys, warns if host is not recognised)
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.WarningPolicy()) # TODO: where is this logged?
ssh.connect(
hostname=settings.OVPN_HOSTNAME,
port=settings.OVPN_PORT,
username=settings.OVPN_USERNAME,
)
return ssh
def managed_exec(ssh, command, close=True):
stdin, stdout, stderr = ssh.exec_command(command)
if close:
ssh.close()
output = "".join(stdout.readlines()).strip()
if output == "":
output = "None."
error = "".join(stderr.readlines()).strip()
message = "Executed: %s Output: %s" % (command, output,)
# on sucess, log output, otherwise raise exception
if stdout.channel.recv_exit_status() == 0:
logger.info(message)
else:
message += " Error: " + error
raise Exception(message)
def is_existing_credit(credit):
matching_credits = ExternalCredit.objects.filter(
parser=credit.parser,
external_key=credit.external_key,
)
is_existing = len(matching_credits) > 0
return is_existing
def get_external_bundle(parser, external_key):
return ExternalBundle.objects.filter(
parser=parser,
external_key=external_key,
)
def activate_single_limit(limit, credit_timedelta=None, renewal_date=None):
is_credit = credit_timedelta is not None
is_renewal = renewal_date is not None
if is_credit == is_renewal:
raise Exception("Invalid activation attempt. Need strictly one of credit or renewal data.")
if is_credit and limit.is_active:
limit.expiry_date += credit_timedelta
elif is_credit and not limit.is_active:
limit.expiry_date = timezone.now() + credit_timedelta
limit.is_active = True
elif is_renewal:
limit.renewal_date = renewal_date
limit.is_active = True
else:
raise Exception("Invalid activation attempt. Unknown condition.")
# skip activation command if we are debugging
if settings.DEBUG_SKIP_ACTIVATION_COMMAND:
limit.save()
return
# otherwise, activate the limit before saving
if limit.service == settings.LM_SERVICES.TUNNEL:
# TUNNEL special case requires user manual activation
limit.is_active = False
elif limit.service == settings.LM_SERVICES.CHAT:
limit.user.set_ldap_group("chat")
limit.is_active = True
elif limit.service == settings.LM_SERVICES.MAIL:
limit.user.set_ldap_group("mail")
limit.is_active = True
elif limit.service == settings.LM_SERVICES.SOCIAL:
limit.user.set_ldap_group("social")
limit.is_active = True
elif limit.service == settings.LM_SERVICES.XMPP:
limit.user.set_ldap_group("xmpp")
limit.is_active = True
elif limit.service == settings.LM_SERVICES.GROUP:
limit.is_active = True
else:
raise Exception("Invalid activation attempt. Service not recognised.")
limit.user.chosenreward.is_pending = False
limit.user.chosenreward.save()
limit.save()
def deactivate_single_limit(ssh, limit):
if limit.service == settings.LM_SERVICES.TUNNEL:
command = "./create_new_ovpn_config --revoke %s" % (limit.user.get_identity(),)
managed_exec(ssh, command, close=False)
limit.is_active = False
limit.save()
def get_limit_objects(credit):
# get and validate local username
suffix = "@" + settings.SITE_DOMAIN
if credit.account_name is None or not str.endswith(credit.account_name, suffix):
raise Exception("Invalid account name: " + str(credit.account_name))
else:
suffix_len = 0 - len(suffix)
username = credit.account_name[:suffix_len]
# get objects (implicit validation that they exist)
external_bundles = get_external_bundle(credit.parser, credit.bundle_key)
limits = []
for bundle in external_bundles:
limit = Limit.objects.get(
user__username=username,
service=bundle.service,
)
limits.append(limit)
return limits
@transaction.atomic
def store_credit_and_update_limit(credit, next_renewal=None):
try:
if credit.parser == "WOO1":
from .tunnel_credit import update_limit_woo1
update_limit_woo1(credit)
elif credit.parser == 2: # FIXME: this is WOO_SUBSCRIPTION_V1 from purist.limitmonitor
from .tunnel_subscription import update_limit_woosub1
update_limit_woosub1(credit, next_renewal)
else:
raise Exception("Unrecognised Parser " + str(credit.parser))
credit.is_converted = True
credit.error_message = ""
except Exception as e:
message = "Skipped adding credit Parser " + str(credit.parser) + ": " + credit.external_key + ". "
logger.exception(message)
credit.error_message = message + repr(e)
finally:
credit.save()
state = "converted" if credit.is_converted else "skipped"
logger.info("Stored " + state + " credit Parser " + str(credit.parser) + ": " + credit.external_key)
def deactivate_all_expired_limits():
# make connection objects
ssh = get_openvpn_ssh_connection()
# get overdue objects and deactivate them
now = timezone.now()
overdue_list = Limit.objects.filter(expiry_date__lte=now, is_active=True)
for limit in overdue_list:
deactivate_single_limit(ssh, limit)
ssh.close()
def debug_connection_task():
# make connection objects
woo_connection = get_woo_connection()
ssh = get_openvpn_ssh_connection()
managed_exec(ssh, "whoami", close=True)
logger.info("Debug task with " + repr(woo_connection) + " and " + repr(ssh) + " completed successfully.")
def purge_users_pending_cart():
pending_carts = ChosenReward.objects.filter(is_pending=True)
......
from .common import *
def get_latest_woo1(connection, product_id):
return connection.get("orders?product=" + str(product_id))
def parse_woo1(json_entry, product_id):
result_list = []
order_name = json_entry["number"]
order_id = json_entry["id"]
for line_item in json_entry["line_items"]:
if line_item["product_id"] == product_id:
item_id = line_item["id"]
product_id = line_item["product_id"]
product_label = line_item["name"]
quantity = line_item["quantity"]
account = None # FIXME: need to get the account
external_key = str(order_id) + ":" + str(item_id)
external_label = str(order_name)
result_list.append({
"parser": "WOO1",
"external_key": external_key,
"label": external_label,
"product_key": product_id,
"product_label": product_label,
"quantity": quantity,
"account": account,
"original_email": "",
"isconverted": False,
})
return result_list
def update_limit_woo1(ssh, credit):
user, limit, external_bundle = get_limit_objects(credit)
credit_days = int(external_bundle.time_credit * credit.quantity)
credit_timedelta = timezone.timedelta(days=credit_days)
activate_single_limit(ssh, limit, credit_timedelta, None)
def monitor_woo1():
# make connection objects
woo_connection = get_woo_connection()
ssh = get_openvpn_ssh_connection()
# get product sales and parse the results
result_list = []
for product_id in settings.WOO_PRODUCT_LIST:
latest_woo1_json = get_latest_woo1(woo_connection, product_id).json()
for json_entry in latest_woo1_json:
try:
result_list.extend(parse_woo1(json_entry, product_id))
except Exception as e:
logger.exception("Skipping JSON entry " + str(json_entry))
# add new results
count = 0
for result in result_list:
try:
credit = ExternalCredit(
parser=result["parser"],
external_key=result["external_key"],
label=result["label"],
bundle_key=result["product_key"],
bundle_label=result["product_label"],
quantity=result["quantity"],
account_name=result["account"],
additional_data=result["original_email"],
is_converted=False,
)
if not is_existing_credit(credit):
store_credit_and_update_limit(ssh, credit)
count += 1
else:
logger.debug("Skipped existing result " + str(result))
except Exception as e:
logger.exception("Skipped bad result " + str(result))
if count > 0:
logger.info("Added %i new results." % (count,))
ssh.close()
import datetime
from .common import *
def parse_woosub1(json_entry):
subscription_id = str(json_entry["id"])
# validation
if len(json_entry["line_items"]) != 1:
raise Exception("Too many line items in subscription %s" % (id, ))
line_item = json_entry["line_items"][0]
quantity = line_item["quantity"]
if quantity != 1:
raise Exception("Bad quantity %s in subscription %s" % (quantity, id, ))
# calculate next renewal date
next_renewal_naive = datetime.datetime.strptime(json_entry["next_payment_date"], "%Y-%m-%dT%H:%M:%S")
next_renewal = timezone.make_aware(next_renewal_naive)
# get account name
username = get_username_from_woo_customer_id(json_entry["customer_id"])
# bundle_key value is different depending on the subscription
# having variations or not
if line_item.get('variation_id') != 0:
bundle_key = line_item.get('variation_id')
else:
bundle_key = line_item.get('product_id')
# create result
result = {
"parser": 2, # FIXME: this is WOO_SUBSCRIPTION_V1 from purist.limitmonitor
"external_key": subscription_id,
"label": json_entry["number"],
"bundle_key": bundle_key,
"bundle_label": str(line_item["name"]),
"quantity": 1,
"account": username,
"next_renewal": next_renewal,
}
return [result, ]
def monitor_woosub1_new_subscriptions():
# make connection objects
woo_connection = get_woo_connection()
# initialise
result_list = []
# TODO: We could also only request subscriptions for specific
# products, the ones in settings.WOOSUB1_PRODUCT_LIST
latest_subscription_json = woo_connection.get('subscriptions?'
'orderby=date&'
'order=desc&'
'status=active').json()
# parse recent subscriptions and store results
for json_entry in latest_subscription_json:
try:
product_id = int(json_entry["line_items"][0]["product_id"])
if product_id in settings.WOOSUB1_PRODUCT_LIST:
result_list.extend(parse_woosub1(json_entry))
except Exception as e:
logger.exception("Skipping JSON entry " + str(json_entry))
# add new results
count = 0
for result in result_list:
try:
credit = ExternalCredit(
parser=result["parser"],
external_key=result["external_key"],
label=result["label"],
bundle_key=result["bundle_key"],
bundle_label=result["bundle_label"],
quantity=result["quantity"],
account_name=result["account"],
additional_data="None",
is_converted=False,
)
if not is_existing_credit(credit):
store_credit_and_update_limit(credit, result["next_renewal"])
count += 1
else:
logger.debug("Skipped existing result " + str(result))
except Exception as e:
logger.exception("Skipped bad result " + str(result))
def update_limit_woosub1(credit, renewal_date):
limits = get_limit_objects(credit)
for limit in limits:
activate_single_limit(limit, None, renewal_date)
if limit:
limit.user.date_joined = datetime.datetime(1900, 1, 1, 0, 0)
limit.user.save()
def monitor_woosub1_renewals():
# make connection objects
woo_connection = get_woo_connection()
ssh = get_openvpn_ssh_connection()
# get objects due for renewal (one hour grace / buffer)
now = timezone.now() - datetime.timedelta(hours=1)
overdue_list = Limit.objects.filter(renewal_date__lte=now,expiry_date=None, is_active=True)
count = 0
for limit in overdue_list:
identity = limit.user.get_identity()
woosub_bundle_list = ExternalBundle.objects.filter(service=limit.service, parser="WOOSUB1")
for bundle in woosub_bundle_list:
woosub_credit = ExternalCredit.objects.get(account_name=identity, bundle_key=bundle.external_key,
parser="WOOSUB1")
try:
subscription_query = "subscriptions/" + woosub_credit.external_key
woosub_json = woo_connection.get(subscription_query).json()
result = parse_woosub1(woosub_json)
# deactivate expired limits
if not result["active"]:
deactivate_single_limit(ssh, limit)
woosub_credit.is_converted = False
woosub_credit.error_message = "Expired."
else:
store_credit_and_update_limit(ssh, woosub_credit, result["renewal"])
woosub_credit.is_converted = True
woosub_credit.error_message = ""
count += 1
except Exception as e:
message = "Skipping bad credit %s (%s)." % (woosub_credit.id, woosub_credit.external_code)
logger.exception(message)
woosub_credit.is_converted = False
woosub_credit.error_message = message + repr(e)
finally:
woosub_credit.save()
if count > 0:
logger.info("Updated %i subscriptions." % (count,))
ssh.close()
from celery import shared_task
from .task_resources import common
from .task_resources import tunnel_credit
from .task_resources import tunnel_subscription
from .task_resources import subscription
@shared_task
def tunnel_refresh_subscription():
tunnel_subscription.monitor_woosub1_renewals()
@shared_task
def tunnel_new_subscription():
tunnel_subscription.monitor_woosub1_new_subscriptions()
@shared_task
def tunnel_new_credit():
tunnel_credit.monitor_woo1()
@shared_task
def deactivate_all_expired_limits():
common.deactivate_all_expired_limits()
@shared_task
def debug_connection_task():
common.debug_connection_task()
@shared_task
def purge_users_pending_cart_task():
common.purge_users_pending_cart()
......
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.http import FileResponse, HttpResponseRedirect
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
......@@ -83,16 +83,6 @@ def userlimit(request):
return render(request, 'limitmonitor/userlimit.html', render_data)
@login_required
def ovpn_userfile(request):
user_identity = request.user.get_identity()
filepath = settings.OVPN_FILEPATH.replace("{USER_IDENTITY}", user_identity)
response = FileResponse(open(filepath, 'rb'), content_type='application/octet-stream')
response['Content-Disposition'] = 'attachment; filename="purist.ovpn"'
return response
@login_required
def toggle_tunnel(request):
tunnel_limit = request.user.limit_set.filter(
......
......@@ -208,15 +208,6 @@ WOO_BUNDLES_INFO_FILE = config(
default='/etc/opt/purist/middleware/upgrades_downgrades.yml'
)
#
# SSH CONNECTION TO OPENVPN SERVER
#
OVPN_HOSTNAME = config("OVPN_HOSTNAME")
OVPN_PORT = config("OVPN_PORT", cast=int)
OVPN_USERNAME = config("OVPN_USERNAME")
OVPN_FILEPATH = config("OVPN_FILEPATH")
#
# LIMIT MONITOR
#
......
......@@ -16,11 +16,11 @@ Including another URLconf
from django.conf.urls import include, url
from django.contrib import admin
from django.views.generic import RedirectView
from registration.backends.simple.views import RegistrationView
# from registration.backends.simple.views import RegistrationView
import limitmonitor.views
import purist.views
from ldapregister.forms import RegistrationForm
# from ldapregister.forms import RegistrationForm
from ldapregister.views import LdhLoginView
from cart.views import CartRegistrationView
......@@ -46,7 +46,6 @@ urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^accounts/$', RedirectView.as_view(url='/')),
url(r'^accounts/profile/$', limitmonitor.views.userlimit, name='profile'),
url(r'^accounts/profile/purist.ovpn', limitmonitor.views.ovpn_userfile, name='ovpn_userfile'),
url(r'^accounts/profile/toggle_tunnel',
limitmonitor.views.toggle_tunnel, name='toggle_tunnel'),
url(r'^accounts/profile/new_invitation',
......
......@@ -17,7 +17,6 @@ from middleware.common import get_woo_connection
from ldapregister.models import LdapPerson, LdapGroup
from limitmonitor import models as limitmonitor_models
from limitmonitor.task_resources import common as limitmonitor_common
from limitmonitor.tunnel import TunnelManager
from limitmonitor.models import get_available_bundles
......@@ -275,16 +274,6 @@ class User(AbstractUser):
# delete invalid credits (they will be re-parsed)
limitmonitor_models.delete_unconverted_user_credits(self)
if