Skip to content

Commit be4452e

Browse files
author
kprice
committed
maybe working
1 parent fdd3c97 commit be4452e

File tree

4 files changed

+97
-9
lines changed

4 files changed

+97
-9
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
""""
2+
Migrations for the 2025 Q4 Authenticator release
3+
"""
4+
5+
from alembic import op
6+
import psycopg2
7+
import sqlalchemy as sa
8+
from tapisservice.config import conf
9+
from tapisservice.logs import get_logger
10+
logger = get_logger(__name__)
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = '25Q4'
15+
down_revision = '1.3.4'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
op.create_table('users',
22+
sa.Column('id', sa.Integer(), nullable=False),
23+
sa.Column('client_id', sa.String(length=80), nullable=False),
24+
sa.Column('username', sa.String(length=50), nullable=False),
25+
sa.Column('always_allow', sa.Boolean(), nullable=False),
26+
sa.PrimaryKeyConstraint('id')
27+
)
28+
29+
30+
def downgrade():
31+
op.drop_table('users')
32+

service/controllers.py

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
DeviceCode,
4848
token_webapp_clients,
4949
tenant_configs_cache,
50+
User
5051
)
5152
from service.ldap import list_tenant_users, get_tenant_user, check_username_password
5253
from service.oauth2ext import OAuth2ProviderExtension
@@ -1270,7 +1271,7 @@ def get(self):
12701271
user_code=request.args.get("user_code", None)
12711272

12721273
mfa_response = check_and_redirect_mfa(
1273-
mfa_config, client_id, client_redirect_uri, client_state, response_type, user_code, session
1274+
mfa_config, client_id, client_redirect_uri, client_state, response_type, user_code
12741275
)
12751276

12761277
if mfa_response:
@@ -1359,6 +1360,7 @@ def get(self):
13591360
response_type=response_type,
13601361
)
13611362
)
1363+
username = session["username"]
13621364
tenant_id = g.request_tenant_id
13631365
if not tenant_id:
13641366
tenant_id = session.get("tenant_id")
@@ -1371,7 +1373,7 @@ def get(self):
13711373
logger.debug(f"No client available; e: {e}")
13721374
context = {
13731375
"error": "",
1374-
"username": session["username"],
1376+
"username": username,
13751377
"tenant_id": tenant_id,
13761378
"client_display_name": display_name,
13771379
"client_id": client_id,
@@ -1382,11 +1384,26 @@ def get(self):
13821384
"user_code": user_code,
13831385
}
13841386

1387+
auto_approve = User.query.filter_by(username=username, client_id=client_id).first()
1388+
if auto_approve is not None:
1389+
auto_approve = True
1390+
13851391
# Add check here for auto approve
1386-
# if auto_approve and not device_code flow:
1387-
# generate_authorization_code()
1388-
# auto_redirect = handle_response_type()
1389-
# return auto_redirect
1392+
logger.debug(f'Checking for auto approve ... ')
1393+
if auto_approve and not is_device_flow:
1394+
logger.debug(f'Found. Skipping authoriziation page.')
1395+
generate_authorization_code(tenant_id, username, client_id, client)
1396+
auto_redirect = handle_response_type(
1397+
response_type,
1398+
allowable_grant_types,
1399+
tenant_id,
1400+
username,
1401+
client_id,
1402+
client,
1403+
client_state
1404+
)
1405+
return auto_redirect
1406+
logger.debug(f'Not found. Proceeding to authentication page')
13901407

13911408
return make_response(render_template("authorize.html", **context), 200, headers)
13921409

@@ -1401,7 +1418,8 @@ def post(self):
14011418
raise errors.ResourceError(
14021419
"Tenant ID missing from session. Please logout and select a tenant."
14031420
)
1404-
client_display_name = request.form.get("client_display_name")
1421+
client_display_name = request.form.get("client_display_name")
1422+
username = None
14051423
try:
14061424
username = session["username"]
14071425
except KeyError:
@@ -1424,6 +1442,7 @@ def post(self):
14241442
)
14251443

14261444
# TODO - move all request form gets to top, remove duplicates
1445+
always_allow = request.form.get("always_allow")
14271446
state = request.form.get("client_state")
14281447
client_response_type = request.form.get("client_response_type")
14291448
client_id = request.form.get("client_id", None)
@@ -1437,14 +1456,26 @@ def post(self):
14371456
logger.debug(f"client not found in db. client_id: {client_id}")
14381457
raise errors.ResourceError(f"Invalid client: {client_id}")
14391458

1459+
# add alawys_allow rule if user has selected
1460+
if always_allow:
1461+
logger.debug(f'{username} has selected to always allow {client}')
1462+
# check if there is already a record for some reason
1463+
record_exists = User.query.filter_by(username=username, client_id=client_id).first()
1464+
logger.debug(f'record exists status: {record_exists} and has type: {type(record_exists)}')
1465+
if not record_exists:
1466+
db.session.add(User(client_id=client_id, username=username, always_allow=True))
1467+
else:
1468+
logger.debug(f'record to always allow {username}: {client} already exists, skipping creation')
1469+
1470+
14401471
# check original response_type passed in by the client and make sure grant type supported by the tenant --
14411472
config = tenant_configs_cache.get_config(tenant_id)
14421473
allowable_grant_types = json.loads(config.allowable_grant_types)
14431474
mfa_config = json.loads(config.mfa_config)
14441475
user_code = request.args.get("user_code", None)
14451476

14461477
mfa_response = check_and_redirect_mfa(
1447-
mfa_config, client_id, client.callback_url, state, client_response_type, user_code, session
1478+
mfa_config, client_id, client.callback_url, state, client_response_type, user_code
14481479
)
14491480

14501481
if mfa_response:
@@ -2353,7 +2384,8 @@ def get(self):
23532384
tenant_id = g.request_tenant_id
23542385
logger.debug(f"client_id: {client_id}; tenant_id: {tenant_id}")
23552386
# get additional query parameters from request ---
2356-
state = request.args.get("state")
2387+
# state = request.args.get("state")
2388+
state = None
23572389
session_state = session.get("state")
23582390
if not state == session_state:
23592391
logger.error(
@@ -2363,6 +2395,7 @@ def get(self):
23632395
msg=f"Unauthorized access attempt: state mismatch."
23642396
)
23652397
code = request.args.get("code")
2398+
logger.debug(f'got code from request:: {code}')
23662399

23672400
# POST to oauth2/tokens (passing code, client id, client secret, and redirect uri)
23682401
logger.debug(f"request.base_url: {request.base_url}")

service/models.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,23 @@ class RefreshTokens(db.Model):
650650
# the last time this record was updated
651651
last_update_time = db.Column(db.DateTime, default=datetime.datetime.utcnow, nullable=False)
652652

653+
class User(db.Model):
654+
__tablename__ = 'users'
655+
656+
id = db.Column(db.Integer, primary_key=True)
657+
client_id = db.Column(db.String(80), unique=False, nullable=False, index=True)
658+
username = db.Column(db.String(50), unique=False, nullable=False, index=True)
659+
always_allow = db.Column(db.Boolean, nullable=False)
660+
661+
@property
662+
def serialize(self):
663+
return {
664+
"client_id": self.client_id,
665+
"username": self.username,
666+
"create_time": self.create_time,
667+
"last_update_time": self.last_update_time,
668+
"always_allow": self.always_allow,
669+
}
653670

654671
class LdapUser(object):
655672
"""

service/templates/authorize.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ <h1>
4343
<footer id="button-container">
4444
<button type="submit" name="approve" value="true" required>Connect</button>
4545
</footer>
46+
<div id="always-allow-field">
47+
<label aria-labelledby="always-allow-label">
48+
Always allow?
49+
<input type="checkbox" id="always_allow" name="always_allow">
50+
</label>
51+
</div>
4652
</form>
4753
</main>
4854
{% endblock %}

0 commit comments

Comments
 (0)