1: <?php
2: /*
3: * SimpleID
4: *
5: * Copyright (C) Kelvin Mo 2014-2025
6: *
7: * This program is free software; you can redistribute it and/or
8: * modify it under the terms of the GNU General Public
9: * License as published by the Free Software Foundation; either
10: * version 2 of the License, or (at your option) any later version.
11: *
12: * This program is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15: * General Public License for more details.
16: *
17: * You should have received a copy of the GNU General Public
18: * License along with this program; if not, write to the Free
19: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20: *
21: */
22:
23: namespace SimpleID\Protocols\OpenID;
24:
25: use SimpleID\Protocols\XRDS\XRDSDiscovery;
26: use SimpleID\Models\Client;
27:
28: /**
29: * A class representing an OpenID ID relying party.
30: *
31: * A relying party is identified based by its discovery URL. The
32: * discovery URL is based on the `openid.realm` parameter, with
33: * the asterisk replaced by `www.`.
34: */
35: class RelyingParty extends Client {
36:
37: // OpenID clients are always dynamic
38: /** @var bool */
39: protected $dynamic = true;
40:
41: /** @var string */
42: private $store_id;
43:
44: /**
45: * @param string $realm
46: */
47: public function __construct($realm) {
48: parent::__construct([
49: 'openid' => [ 'realm' => $realm, 'services' => NULL, 'discovery_time' => 0 ]
50: ]);
51: $this->cid = $realm;
52: $this->store_id = self::buildID($realm);
53: }
54:
55: /**
56: * Returns the realm
57: *
58: * @return string the realm
59: */
60: public function getRealm() {
61: return $this->container['openid']['realm'];
62: }
63:
64: /**
65: * Returns the discovered XRDS services.
66: *
67: * Note that these discovered services may not be current. The time
68: * discovery was last made can be obtained from {@link getDiscoveryTime()}.
69: *
70: * @return \SimpleID\Protocols\XRDS\XRDSServices the XRDS services or null
71: */
72: public function getServices() {
73: return $this->container['openid']['services'];
74: }
75:
76: /**
77: * Returns the time when discovery was most recently performed.
78: *
79: * @return int the time, or 0 if discovery was never performed for this
80: * relying party
81: */
82: public function getDiscoveryTime() {
83: return $this->container['openid']['discovery_time'];
84: }
85:
86: /**
87: * Performs XRDS discovery on this relying party.
88: *
89: * @return void
90: */
91: public function discover() {
92: $discovery = XRDSDiscovery::instance();
93: $url = self::getDiscoveryURL($this->getRealm());
94: $this->container['openid']['services'] = $discovery->discover($url);
95: }
96:
97: /**
98: * Returns the URL of a relying party endpoint for a specified realm. This URL
99: * is used to discover services associated with the realm.
100: *
101: * If the realm's domain contains the wild-card characters "*.", this is substituted
102: * with "www.".
103: *
104: * @param string $realm the realm
105: * @return string the URL
106: *
107: * @since 0.7
108: */
109: protected static function getDiscoveryURL($realm) {
110: $parts = parse_url($realm);
111: if ($parts == false) return $realm;
112: $host = strtr($parts['host'], [ '*.' => 'www.' ]);
113:
114: $url = $parts['scheme'] . '://';
115: if (isset($parts['user'])) {
116: $url .= $parts['user'];
117: if (isset($parts['pass'])) $url .= ':' . $parts['pass'];
118: $url .= '@';
119: }
120: $url .= $host;
121: if (isset($parts['port'])) $url .= ':' . $parts['port'];
122: if (isset($parts['path'])) $url .= $parts['path'];
123: if (isset($parts['query'])) $url .= '?' . $parts['query'];
124: if (isset($parts['fragment'])) $url .= '#' . $parts['fragment'];
125: return $url;
126: }
127:
128: /**
129: * @param string $realm
130: * @return string
131: */
132: public static function buildID($realm) {
133: $url = self::getDiscoveryURL($realm);
134: return '_' . trim(strtr(base64_encode(sha1($url, true)), '+/', '-_'), '=') . '.openid';
135: }
136:
137: public function getStoreID() {
138: return $this->store_id;
139: }
140:
141: public function setStoreID($id) {
142: $this->store_id = $id;
143: }
144:
145: public function getDisplayName() {
146: return preg_replace('@^https?://(www\.|\*\.)?@', '', $this->getRealm());
147: }
148:
149: public function getDisplayHTML() {
150: return preg_replace('@^https?://(www\.|\*\.)?@', '<span class="url-elide">$0</span>', $this->getRealm());
151: }
152: }
153:
154: ?>