1: <?php
2: /*
3: * SimpleID
4: *
5: * Copyright (C) Kelvin Mo 2014-2026
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: if (!isset($parts['scheme']) || !isset($parts['host'])) return $realm;
113: $host = strtr($parts['host'], [ '*.' => 'www.' ]);
114:
115: $url = $parts['scheme'] . '://';
116: if (isset($parts['user'])) {
117: $url .= $parts['user'];
118: if (isset($parts['pass'])) $url .= ':' . $parts['pass'];
119: $url .= '@';
120: }
121: $url .= $host;
122: if (isset($parts['port'])) $url .= ':' . $parts['port'];
123: if (isset($parts['path'])) $url .= $parts['path'];
124: if (isset($parts['query'])) $url .= '?' . $parts['query'];
125: if (isset($parts['fragment'])) $url .= '#' . $parts['fragment'];
126: return $url;
127: }
128:
129: /**
130: * @param string $realm
131: * @return string
132: */
133: public static function buildID($realm) {
134: $url = self::getDiscoveryURL($realm);
135: return '_' . trim(strtr(base64_encode(sha1($url, true)), '+/', '-_'), '=') . '.openid';
136: }
137:
138: public function getStoreID() {
139: return $this->store_id;
140: }
141:
142: public function setStoreID($id) {
143: $this->store_id = $id;
144: }
145:
146: public function getDisplayName() {
147: return preg_replace('@^https?://(www\.|\*\.)?@', '', $this->getRealm());
148: }
149:
150: public function getDisplayHTML() {
151: return preg_replace('@^https?://(www\.|\*\.)?@', '<span class="url-elide">$0</span>', $this->getRealm());
152: }
153: }
154:
155: ?>