dh_ackergaul
vor 3 Tagen 5bbf43c1b146439ab882815c12ed6292f1d7b4df
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
const uuid = require("node-uuid").v4;
 
const { BaseAuthenticationService } = require("./BaseAuthenticationService");
 
module.exports.OAuth2AuthenticationService = class extends BaseAuthenticationService {
    constructor() {
        super();
 
        this.discover();
    }
 
    async discover() {
        try {
            this.openId = await import("@dh-software/opus-x-openid-client-helper");
 
            this.config = await this.openId.getConfig(sails.config.oauth, true);
 
            console.log(`Discovered OAuth Service: ${this.config.serverMetadata().issuer}`);
        }
        catch (error) {
            console.error(`Unable to discover OAuth Server at ${sails.config.oauth.issuer}. Retrying...`, error);
 
            this.config = undefined;
 
            setTimeout(() => this.discover(), 3000);
        }
    }
 
    async login(req, res) {
        try {
            const { codeVerifier, state, url } = await this.openId.getAuthenticationAttempt(this.config, sails.config.oauth.redirectUri);
 
            req.auth_cookie.auth = {
                codeVerifier,
                state,
                originalUrl: req.query.oriReq || "/"
            };
 
            return res.redirect(url.href);
        }
        catch (e) {
            Winston.error("OAuth login initiation failed:", e);
 
            return res.serverError();
        }
    }
 
    async logout(req, res) {
        try {
            const uri = await this.openId.buildLogoutURL(this.config, sails.config.oauth.postLogoutRedirectURIs[0], req.user.get("oauth.idToken"));
 
            return res.json({ url: uri.toString() });
        }
        catch (error) {
            console.error("Unable to logout:", error);
 
            return res.serverError();
        }
    }
 
    async callback (req, res) {
        const oauthSession = req.auth_cookie.auth;
 
        if (!oauthSession || req.query.state !== oauthSession.state) {
            Winston.warn("OAuth callback state mismatch or missing session");
            return res.redirect("/auth/login");
        }
 
        try {
            const callbackUrl = new URL(
                req.url,
                sails.config.oauth.redirectUri
            );
 
            const { userInfo, tokenSet } = await this.openId.callback(this.config, oauthSession.codeVerifier, oauthSession.state, callbackUrl);
 
            if (!userInfo.sub || !userInfo.customer_no) {
                console.error("OAuth callback missing required userInfo 'sub' or 'customer_no':", userInfo);
 
                delete req.auth_cookie.auth;
 
                return res.redirect("/auth/login");
            }
 
            const opusSessionId = uuid();
 
            const user = {
                _id: opusSessionId,
                permissions: ["anonymous", "basic", "dhp"],
                canLogout: true,
                isOpusUser: true,
                canSeeEverything: false,
                customerNo: userInfo.customer_no,
                username: userInfo.username,
                opusSessionId: opusSessionId,
                data: {},
                oauth: {
                    idToken: tokenSet.id_token,
                    userInfo: userInfo,
                }
            };
 
            const configuration = await UseCaseConfiguration.findOne({
                customerNo: user.customerNo,
                externalConf: true
            });
 
            if (configuration) user.data.config = configuration.id;
 
            await Session.update({ _id: req.session._id }, { $addToSet: { users: user } });
 
            console.log("OAuth login granted for subject:", userInfo.sub, "username:", userInfo.username, "customerNo:", userInfo.customer_no);
 
            const redirectTo = new URL("http://" + req.headers["host"] + req.auth_cookie.auth.originalUrl);
 
            redirectTo.searchParams.set("session", user.opusSessionId);
 
            return res.redirect(redirectTo.toString());
        }
        catch (e) {
            console.error("OAuth login callback failed: ", e);
 
            return res.redirect("/auth/login");
        }
        finally {
            delete req.auth_cookie.auth;
        }
    }
 
    async backchannelLogout (req, res) {
        try {
            const claims = await this.openId.validateLogoutToken(this.config, req.body.logout_token);
            const session = await Session.findOne({ "users.oauth.userInfo.sub": claims.sub });
            const user = session.users.find((user) => user?.get("oauth")?.userInfo?.sub === claims.sub);
 
            const { userInfo } = user.get("oauth");
 
            await Session.update({ _id: session._id }, { $pull: { users: { "oauth.userInfo.sub": claims.sub } } });
 
            if (req.session) {
                // delete temporary session which was created as a fallback (config/http.js) when the OAuth server called the logout callback
                await Session.deleteOne({ _id: req.session._id });
            }
 
            console.log("OAuth logout granted for subject:", userInfo.sub, "username:", userInfo.username, "customerNo:", userInfo.customer_no);
        }
        catch (error) {
            console.warn("Unable to single sign off:", error);
        }
 
        return res.send("ok");
    }
};