aboutsummaryrefslogtreecommitdiff
path: root/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2Session.cs
blob: 916f55c78a3234647543172f9ba096ea9588a02b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
* Copyright (c) 2022 Vaughn Nugent
* 
* Library: VNLib
* Package: VNLib.Plugins.Essentials.Sessions.OAuth
* File: OAuth2Session.cs 
*
* OAuth2Session.cs is part of VNLib.Plugins.Essentials.Sessions.OAuth which is part of the larger 
* VNLib collection of libraries and utilities.
*
* VNLib.Plugins.Essentials.Sessions.OAuth is free software: you can redistribute it and/or modify 
* it under the terms of the GNU Affero General Public License as 
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* VNLib.Plugins.Essentials.Sessions.OAuth is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see https://www.gnu.org/licenses/.
*/

using System;
using System.Threading;
using System.Threading.Tasks;

using VNLib.Net.Http;
using VNLib.Plugins.Essentials.Sessions;
using VNLib.Plugins.Sessions.Cache.Client;
using VNLib.Plugins.Sessions.Cache.Client.Exceptions;

using static VNLib.Plugins.Essentials.Sessions.ISessionExtensions;

namespace VNLib.Plugins.Sessions.OAuth
{
    /// <summary>
    /// The implementation of the OAuth2 session container for HTTP sessions
    /// </summary>
    internal sealed class OAuth2Session : RemoteSession
    {
        private readonly Action<OAuth2Session> InvalidateCache;

        /// <summary>
        /// Initalizes a new <see cref="OAuth2Session"/>
        /// </summary>
        /// <param name="sessionId">The session id (or token)</param>
        /// <param name="client">The <see cref="IRemoteCacheStore"/> used as the backing cache provider</param>
        /// <param name="backgroundTimeOut">The ammount of time to wait for a background operation (delete, update, get)</param>
        /// <param name="invalidCache">Called when the session has been marked as invalid and the close even hook is being executed</param>
        public OAuth2Session(string sessionId, IRemoteCacheStore client, TimeSpan backgroundTimeOut, Action<OAuth2Session> invalidCache)
            : base(sessionId, client, backgroundTimeOut)
        {
            InvalidateCache = invalidCache;
            IsInvalid = false;
        }

        public bool IsInvalid { get; private set; }


        ///<inheritdoc/>
        ///<exception cref="NotSupportedException"></exception>
        public override string Token
        {
            get => throw new NotSupportedException("Token property is not supported for OAuth2 sessions");
            set => throw new NotSupportedException("Token property is not supported for OAuth2 sessions");
        }

        ///<inheritdoc/>
        protected override void IndexerSet(string key, string value)
        {
            //Guard protected entires
            switch (key)
            {
                case TOKEN_ENTRY:
                case LOGIN_TOKEN_ENTRY:
                    throw new InvalidOperationException("Token entry may not be changed!");
            }
            base.IndexerSet(key, value);
        }
        ///<inheritdoc/>
        ///<exception cref="SessionStatusException"></exception>
        public override async Task WaitAndLoadAsync(IHttpEvent entity, CancellationToken token = default)
        {
            //Wait to enter lock
            await base.WaitAndLoadAsync(entity, token);
            if (IsInvalid)
            {
                //Release lock
                MainLock.Release();
                throw new SessionStatusException("The session has been invalidated");
            }
            //Set session type
            if (IsNew)
            {
                SessionType = SessionType.OAuth2;
            }
        }
        ///<inheritdoc/>
        protected override async ValueTask<Task?> UpdateResource(bool isAsync, IHttpEvent state)
        {
            Task? result = null;
            //Invalid flag is set, so exit
            if (IsInvalid)
            {
                result = Task.CompletedTask;
            }
            //Check flags in priority level, Invalid is highest state priority
            else if (Flags.IsSet(INVALID_MSK))
            {
                //Clear all stored values
                DataStore!.Clear();
                //Delete the entity syncronously
                await ProcessDeleteAsync();
                //Set invalid flag
                IsInvalid = true;
                //Invlidate cache
                InvalidateCache(this);
                result = Task.CompletedTask;
            }
            else if (Flags.IsSet(MODIFIED_MSK))
            {
                //Send update to server
                result = Task.Run(ProcessUpdateAsync);
            }
            
            //Clear all flags
            Flags.ClearAll();
            
            return result;
        }
    }
}