Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
O
Openfire
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Openfire
Commits
321c282d
Commit
321c282d
authored
Jan 26, 2018
by
Guus der Kinderen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
OF-1469 New plugin: XEP-0215 External Service Discovery
parent
3e926a78
Changes
30
Show whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
2217 additions
and
0 deletions
+2217
-0
changelog.html
src/plugins/externalservicediscovery/changelog.html
+52
-0
logo_large.png
src/plugins/externalservicediscovery/logo_large.png
+0
-0
logo_small.png
src/plugins/externalservicediscovery/logo_small.png
+0
-0
plugin.xml
src/plugins/externalservicediscovery/plugin.xml
+20
-0
pom.xml
src/plugins/externalservicediscovery/pom.xml
+56
-0
readme.html
src/plugins/externalservicediscovery/readme.html
+94
-0
externalservicediscovery_db2.sql
...cediscovery/src/database/externalservicediscovery_db2.sql
+16
-0
externalservicediscovery_hsqldb.sql
...iscovery/src/database/externalservicediscovery_hsqldb.sql
+16
-0
externalservicediscovery_mysql.sql
...discovery/src/database/externalservicediscovery_mysql.sql
+16
-0
externalservicediscovery_oracle.sql
...iscovery/src/database/externalservicediscovery_oracle.sql
+16
-0
externalservicediscovery_postgresql.sql
...very/src/database/externalservicediscovery_postgresql.sql
+16
-0
externalservicediscovery_sqlserver.sql
...overy/src/database/externalservicediscovery_sqlserver.sql
+16
-0
externalservicediscovery_sybase.sql
...iscovery/src/database/externalservicediscovery_sybase.sql
+16
-0
externalservicediscovery_i18n_en.properties
...very/src/i18n/externalservicediscovery_i18n_en.properties
+47
-0
Credentials.java
...penfire/plugins/externalservicediscovery/Credentials.java
+104
-0
ExternalServiceDiscoveryIQHandler.java
...alservicediscovery/ExternalServiceDiscoveryIQHandler.java
+199
-0
ExternalServiceDiscoveryIQHandlerV1.java
...servicediscovery/ExternalServiceDiscoveryIQHandlerV1.java
+96
-0
ExternalServiceDiscoveryIQHandlerV2.java
...servicediscovery/ExternalServiceDiscoveryIQHandlerV2.java
+110
-0
ExternalServiceDiscoveryPlugin.java
...ernalservicediscovery/ExternalServiceDiscoveryPlugin.java
+90
-0
Service.java
...me/openfire/plugins/externalservicediscovery/Service.java
+407
-0
ServiceManager.java
...fire/plugins/externalservicediscovery/ServiceManager.java
+367
-0
ServiceTest.java
...penfire/plugins/externalservicediscovery/ServiceTest.java
+80
-0
web.xml
src/plugins/externalservicediscovery/src/web/WEB-INF/web.xml
+6
-0
external-service-discovery-config.jsp
...cediscovery/src/web/external-service-discovery-config.jsp
+376
-0
delete-16x16.gif
.../externalservicediscovery/src/web/images/delete-16x16.gif
+0
-0
error-16x16.gif
...s/externalservicediscovery/src/web/images/error-16x16.gif
+0
-0
info-16x16.gif
...ns/externalservicediscovery/src/web/images/info-16x16.gif
+0
-0
success-16x16.gif
...externalservicediscovery/src/web/images/success-16x16.gif
+0
-0
warning-16x16.gif
...externalservicediscovery/src/web/images/warning-16x16.gif
+0
-0
pom.xml
src/plugins/pom.xml
+1
-0
No files found.
src/plugins/externalservicediscovery/changelog.html
0 → 100644
View file @
321c282d
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>
External Service Discovery Plugin Changelog
</title>
<style
type=
"text/css"
>
BODY
{
font-size
:
100%
;
}
BODY
,
TD
,
TH
{
font-family
:
tahoma
,
verdana
,
arial
,
helvetica
,
sans-serif
;
font-size
:
0.8em
;
}
H2
{
font-size
:
10pt
;
font-weight
:
bold
;
padding-left
:
1em
;
}
A
:hover
{
text-decoration
:
none
;
}
H1
{
font-family
:
tahoma
,
arial
,
helvetica
,
sans-serif
;
font-size
:
1.4em
;
font-weight
:
bold
;
border-bottom
:
1px
#ccc
solid
;
padding-bottom
:
2px
;
}
TT
{
font-family
:
courier
new
;
font-weight
:
bold
;
color
:
#060
;
}
PRE
{
font-family
:
courier
new
;
font-size
:
100%
;
}
</style>
</head>
<body>
<h1>
External Service Discovery Plugin Changelog
</h1>
<p><b>
1.0.0
</b>
-- January 26, 2018
</p>
<ul>
<li>
Initial release.
</li>
</ul>
</body>
</html>
src/plugins/externalservicediscovery/logo_large.png
0 → 100644
View file @
321c282d
1.49 KB
src/plugins/externalservicediscovery/logo_small.png
0 → 100644
View file @
321c282d
798 Bytes
src/plugins/externalservicediscovery/plugin.xml
0 → 100644
View file @
321c282d
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<class>
org.igniterealtime.openfire.plugins.externalservicediscovery.ExternalServiceDiscoveryPlugin
</class>
<name>
External Service Discovery
</name>
<description>
Allows XMPP entities to discover services external to the XMPP network, such as STUN and TURN servers.
</description>
<author>
Guus der Kinderen
</author>
<version>
1.0.0
</version>
<date>
01/26/2018
</date>
<databaseKey>
externalservicediscovery
</databaseKey>
<databaseVersion>
1
</databaseVersion>
<adminconsole>
<tab
id=
"sidebar-media-services"
>
<item
id=
"external-service-discovery-config"
name=
"${sidebar.external-service-discovery}"
url=
"external-service-discovery-config.jsp"
description=
"${sidebar.external-service-discovery.descr}"
/>
</tab>
</adminconsole>
</plugin>
src/plugins/externalservicediscovery/pom.xml
0 → 100644
View file @
321c282d
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<parent>
<artifactId>
plugins
</artifactId>
<groupId>
org.igniterealtime.openfire
</groupId>
<version>
4.3.0-SNAPSHOT
</version>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<groupId>
org.igniterealtime.openfire.plugins
</groupId>
<artifactId>
externalservicediscovery
</artifactId>
<version>
1.0.0
</version>
<name>
External Service Discovery Plugin
</name>
<description>
Openfire plugin that implements XEP-0215: External Service Discovery, allowing XMPP entities to discover services external to the XMPP network.
</description>
<build>
<sourceDirectory>
src/java
</sourceDirectory>
<testSourceDirectory>
src/test
</testSourceDirectory>
<plugins>
<plugin>
<artifactId>
maven-assembly-plugin
</artifactId>
</plugin>
<!-- Compiles the Openfire Admin Console JSP pages. -->
<plugin>
<groupId>
org.eclipse.jetty
</groupId>
<artifactId>
jetty-jspc-maven-plugin
</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Versions of Openfire up to 4.2.1 included an older slf4j-api artifact (1.6.6). Fixating the dependency. -->
<dependency>
<groupId>
org.slf4j
</groupId>
<artifactId>
slf4j-api
</artifactId>
<version>
1.7.25
</version>
</dependency>
<dependency>
<groupId>
junit
</groupId>
<artifactId>
junit
</artifactId>
<version>
4.12
</version>
<scope>
test
</scope>
</dependency>
<dependency>
<groupId>
nl.jqno.equalsverifier
</groupId>
<artifactId>
equalsverifier
</artifactId>
<version>
2.4
</version>
<scope>
test
</scope>
</dependency>
</dependencies>
</project>
src/plugins/externalservicediscovery/readme.html
0 → 100644
View file @
321c282d
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>
External Service Discovery Plugin Readme
</title>
<style
type=
"text/css"
>
BODY
{
font-size
:
100%
;
}
BODY
,
TD
,
TH
{
font-family
:
tahoma
,
verdana
,
arial
,
helvetica
,
sans-serif
;
font-size
:
0.8em
;
}
H3
{
font-size
:
10pt
;
font-style
:
italic
;
color
:
#004444
;
}
H2
{
font-size
:
10pt
;
font-weight
:
bold
;
}
A
:hover
{
text-decoration
:
none
;
}
H1
{
font-family
:
tahoma
,
arial
,
helvetica
,
sans-serif
;
font-size
:
1.4em
;
font-weight
:
bold
;
border-bottom
:
1px
#ccc
solid
;
padding-bottom
:
2px
;
}
TT
{
font-family
:
courier
new
;
font-weight
:
bold
;
color
:
#060
;
}
PRE
{
font-family
:
courier
new
;
font-size
:
100%
;
}
#datatable
TH
{
color
:
#fff
;
background-color
:
#2A448C
;
text-align
:
left
;
}
#datatable
TD
{
background-color
:
#FAF6EF
;
}
#datatable
.name
{
background-color
:
#DCE2F5
;
}
</style>
</head>
<body>
<h1>
External Service Discovery Plugin Readme
</h1>
<h2>
Overview
</h2>
<p>
The External Service Discovery plugin allows XMPP entities to discover services that are external to the XMPP
network. It is typically used to allow clients to interact with STUN and TURN services, possibly making use of
temporary credentials for those servers. This plugin provides an implementation of
<a
href=
"https://xmpp.org/extensions/xep-0215.html"
>
XEP-0215: External Service Discovery
</a>
.
</p>
<h2>
Installation
</h2>
<p>
Copy externalservicediscovery.jar into the plugins directory of your Openfire installation. The plugin will then be
automatically deployed. To upgrade to a new version, copy the new externalservicediscovery.jar file over the
existing file.
</p>
<h2>
Configuration
</h2>
<p>
The plugin is configured via the Openfire Admin Console. After installation, a new Admin Console page is available.
The page can be found on a main menu in the "Server" tab, "Media Services" sub-tab. The name of the page is
"Ext. Service Discovery".
</p>
<h2>
Attribution
</h2>
<p>
Icons made by
<a
href=
"http://www.freepik.com"
title=
"Freepik"
>
Freepik
</a>
from
<a
href=
"https://www.flaticon.com/"
title=
"Flaticon"
>
www.flaticon.com
</a>
is licensed by
<a
href=
"http://creativecommons.org/licenses/by/3.0/"
title=
"Creative Commons BY 3.0"
target=
"_blank"
>
CC 3.0 BY
</a>
</p>
</body>
</html>
src/plugins/externalservicediscovery/src/database/externalservicediscovery_db2.sql
0 → 100644
View file @
321c282d
CREATE
TABLE
ofExternalServices
(
serviceID
INT
NOT
NULL
,
name
VARCHAR
(
255
),
host
VARCHAR
(
255
)
NOT
NULL
,
port
INT
,
restricted
BOOLEAN
,
transport
CHAR
(
3
),
type
VARCHAR
(
10
)
NOT
NULL
,
username
VARCHAR
(
255
),
password
VARCHAR
(
1024
),
sharedSecret
VARCHAR
(
1024
)
);
INSERT
INTO
ofID
(
idType
,
id
)
VALUES
(
937
,
1
);
INSERT
INTO
ofVersion
(
name
,
version
)
VALUES
(
'externalservicediscovery'
,
1
);
src/plugins/externalservicediscovery/src/database/externalservicediscovery_hsqldb.sql
0 → 100644
View file @
321c282d
CREATE
TABLE
ofExternalServices
(
serviceID
BIGINT
NOT
NULL
,
name
VARCHAR
(
255
),
host
VARCHAR
(
255
)
NOT
NULL
,
port
INT
,
restricted
BOOLEAN
,
transport
CHAR
(
3
),
type
VARCHAR
(
10
)
NOT
NULL
,
username
VARCHAR
(
255
),
password
VARCHAR
(
1024
),
sharedSecret
VARCHAR
(
1024
)
);
INSERT
INTO
ofID
(
idType
,
id
)
VALUES
(
937
,
1
);
INSERT
INTO
ofVersion
(
name
,
version
)
VALUES
(
'externalservicediscovery'
,
1
);
src/plugins/externalservicediscovery/src/database/externalservicediscovery_mysql.sql
0 → 100644
View file @
321c282d
CREATE
TABLE
ofExternalServices
(
serviceID
BIGINT
NOT
NULL
,
name
VARCHAR
(
255
),
host
VARCHAR
(
255
)
NOT
NULL
,
port
INT
,
restricted
BOOLEAN
,
transport
CHAR
(
3
),
type
VARCHAR
(
10
)
NOT
NULL
,
username
VARCHAR
(
255
),
password
VARCHAR
(
1024
),
sharedSecret
VARCHAR
(
1024
)
);
INSERT
INTO
ofID
(
idType
,
id
)
VALUES
(
937
,
1
);
INSERT
INTO
ofVersion
(
name
,
version
)
VALUES
(
'externalservicediscovery'
,
1
);
src/plugins/externalservicediscovery/src/database/externalservicediscovery_oracle.sql
0 → 100644
View file @
321c282d
CREATE
TABLE
ofExternalServices
(
serviceID
INTEGER
NOT
NULL
,
name
VARCHAR2
(
255
),
host
VARCHAR2
(
255
)
NOT
NULL
,
port
INT
,
restricted
SMALLINT
,
transport
CHAR
(
3
),
type
VARCHAR2
(
10
)
NOT
NULL
,
username
VARCHAR2
(
255
),
password
VARCHAR2
(
1024
),
sharedSecret
VARCHAR2
(
1024
)
);
INSERT
INTO
ofID
(
idType
,
id
)
VALUES
(
937
,
1
);
INSERT
INTO
ofVersion
(
name
,
version
)
VALUES
(
'externalservicediscovery'
,
1
);
src/plugins/externalservicediscovery/src/database/externalservicediscovery_postgresql.sql
0 → 100644
View file @
321c282d
CREATE
TABLE
ofExternalServices
(
serviceID
BIGINT
NOT
NULL
,
name
VARCHAR
(
255
),
host
VARCHAR
(
255
)
NOT
NULL
,
port
INT
,
restricted
BOOLEAN
,
transport
CHAR
(
3
),
type
VARCHAR
(
10
)
NOT
NULL
,
username
VARCHAR
(
255
),
password
VARCHAR
(
1024
),
sharedSecret
VARCHAR
(
1024
)
);
INSERT
INTO
ofID
(
idType
,
id
)
VALUES
(
937
,
1
);
INSERT
INTO
ofVersion
(
name
,
version
)
VALUES
(
'externalservicediscovery'
,
1
);
src/plugins/externalservicediscovery/src/database/externalservicediscovery_sqlserver.sql
0 → 100644
View file @
321c282d
CREATE
TABLE
ofExternalServices
(
serviceID
INTEGER
NOT
NULL
,
name
NVARCHAR
(
255
),
host
NVARCHAR
(
255
)
NOT
NULL
,
port
INT
,
restricted
BIT
,
transport
NCHAR
(
3
),
type
NVARCHAR
(
10
)
NOT
NULL
,
username
NVARCHAR
(
255
),
password
NVARCHAR
(
1024
),
sharedSecret
NVARCHAR
(
1024
)
);
INSERT
INTO
ofID
(
idType
,
id
)
VALUES
(
937
,
1
);
INSERT
INTO
ofVersion
(
name
,
version
)
VALUES
(
'externalservicediscovery'
,
1
);
src/plugins/externalservicediscovery/src/database/externalservicediscovery_sybase.sql
0 → 100644
View file @
321c282d
CREATE
TABLE
ofExternalServices
(
serviceID
INTEGER
NOT
NULL
,
name
NVARCHAR
(
255
),
host
NVARCHAR
(
255
)
NOT
NULL
,
port
INT
,
restricted
BIT
,
transport
NCHAR
(
3
),
type
NVARCHAR
(
10
)
NOT
NULL
,
username
NVARCHAR
(
255
),
password
NVARCHAR
(
1024
),
sharedSecret
NVARCHAR
(
1024
)
);
INSERT
INTO
ofID
(
idType
,
id
)
VALUES
(
937
,
1
);
INSERT
INTO
ofVersion
(
name
,
version
)
VALUES
(
'externalservicediscovery'
,
1
);
src/plugins/externalservicediscovery/src/i18n/externalservicediscovery_i18n_en.properties
0 → 100644
View file @
321c282d
global.csrf.failed
=
CSRF Error: No changes made, you'll need to retry.
global.click_delete
=
Delete
admin.error
=
Internal server error
sidebar.external-service-discovery
=
Ext. Service Discovery
sidebar.external-service-discovery.descr
=
Settings that allow users to detect and use STUN and TURN services that are offered by external servers.
external-service-discovery-config.success-delete
=
Service removed.
external-service-discovery-config.success-add
=
Service added.
external-service-discovery-config.title
=
External Service Discovery Configuration
external-service-discovery-config.descr
=
On this page, you can configure external services (like STUN and TURN servers) that can be used by your users.
external-service-discovery-config.host
=
Host
external-service-discovery-config.host-required
=
A 'host' value is required.
external-service-discovery-config.port
=
Port
external-service-discovery-config.port-number
=
The 'port' value must be numeric.
external-service-discovery-config.name
=
Description
external-service-discovery-config.transport
=
Transport
external-service-discovery-config.tcp
=
TCP
external-service-discovery-config.udp
=
UDP
external-service-discovery-config.type
=
Type
external-service-discovery-config.type-required
=
A 'type' value is required.
external-service-discovery-config.stun
=
STUN
external-service-discovery-config.turn
=
TURN
external-service-discovery-config.turns
=
TURNS
external-service-discovery-config.credentials
=
Credentials
external-service-discovery-config.table.empty
=
There currently are no external services configured.
external-service-discovery-config.add-service.title
=
Add External Service
external-service-discovery-config.add-service.descr
=
You can add an external service by filling out the form below.
external-service-discovery-config.add-service.button-caption
=
Add Service
external-service-discovery-config.credentials.nocredentials
=
No credentials needed
external-service-discovery-config.credentials.using-nocredentials
=
Not using any credentials (implies unauthenticated access)
external-service-discovery-config.credentials.userpass
=
Hardcoded
external-service-discovery-config.credentials.using-userpass
=
Using hardcoded credentials with username:
external-service-discovery-config.credentials.username
=
Username
external-service-discovery-config.credentials.username-required
=
When using hardcoded credentials, a 'username' value is required.
external-service-discovery-config.credentials.password
=
Password
external-service-discovery-config.credentials.password-required
=
When using hardcoded credentials, a 'password' value is required.
external-service-discovery-config.credentials.sharedsecret
=
Shared Secret (for generating ephemeral passwords)
external-service-discovery-config.credentials.sharedsecret-required
=
When generating ephemeral passwords, a 'shared secret' value is required.
external-service-discovery-config.credentials.using-sharedsecret
=
Using shared secret to generate ephemeral passwords.
src/plugins/externalservicediscovery/src/java/org/igniterealtime/openfire/plugins/externalservicediscovery/Credentials.java
0 → 100644
View file @
321c282d
/*
* Copyright (C) 2017 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
igniterealtime
.
openfire
.
plugins
.
externalservicediscovery
;
import
java.util.Date
;
/**
* Representation of service credentials.
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
*/
public
class
Credentials
{
/**
* A timestamp indicating when the provided username and password credentials will expire. The format MUST adhere
* to the dateTime format specified in XMPP Date and Time Profiles (XEP-0082) [12] and MUST be expressed in UTC.
*
* Optional.
*/
private
final
Date
expires
;
/**
* A service- or server-generated password for use at the service.
*
* Optional.
*/
private
final
String
password
;
/**
* A service- or server-generated username for use at the service.
*
* Optional.
*/
private
final
String
username
;
public
Credentials
(
String
username
,
String
password
,
Date
expires
)
{
this
.
username
=
username
;
this
.
password
=
password
;
this
.
expires
=
expires
;
}
public
Date
getExpires
()
{
return
expires
;
}
public
String
getPassword
()
{
return
password
;
}
public
String
getUsername
()
{
return
username
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
{
return
true
;
}
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
()
)
{
return
false
;
}
final
Credentials
that
=
(
Credentials
)
o
;
if
(
expires
!=
null
?
!
expires
.
equals
(
that
.
expires
)
:
that
.
expires
!=
null
)
{
return
false
;
}
if
(
password
!=
null
?
!
password
.
equals
(
that
.
password
)
:
that
.
password
!=
null
)
{
return
false
;
}
return
username
!=
null
?
username
.
equals
(
that
.
username
)
:
that
.
username
==
null
;
}
@Override
public
int
hashCode
()
{
int
result
=
expires
!=
null
?
expires
.
hashCode
()
:
0
;
result
=
31
*
result
+
(
password
!=
null
?
password
.
hashCode
()
:
0
);
result
=
31
*
result
+
(
username
!=
null
?
username
.
hashCode
()
:
0
);
return
result
;
}
}
src/plugins/externalservicediscovery/src/java/org/igniterealtime/openfire/plugins/externalservicediscovery/ExternalServiceDiscoveryIQHandler.java
0 → 100644
View file @
321c282d
/*
* Copyright (C) 2017 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
igniterealtime
.
openfire
.
plugins
.
externalservicediscovery
;
import
org.dom4j.Element
;
import
org.jivesoftware.openfire.auth.UnauthorizedException
;
import
org.jivesoftware.openfire.disco.ServerFeaturesProvider
;
import
org.jivesoftware.openfire.handler.IQHandler
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.xmpp.packet.IQ
;
import
org.xmpp.packet.PacketError
;
import
java.util.Collections
;
import
java.util.Iterator
;
import
java.util.Map
;
/**
* An IQ handler that implements XEP-0215: External Service Discovery.
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
* @see <a href="https://xmpp.org/extensions/xep-0215.html">XEP-0215: External Service Discovery</a>
*/
public
abstract
class
ExternalServiceDiscoveryIQHandler
extends
IQHandler
implements
ServerFeaturesProvider
{
private
static
final
Logger
Log
=
LoggerFactory
.
getLogger
(
ExternalServiceDiscoveryIQHandler
.
class
);
public
ExternalServiceDiscoveryIQHandler
()
{
super
(
"XEP-0215: External Service Discovery"
);
}
@Override
public
Iterator
<
String
>
getFeatures
()
{
return
Collections
.
singleton
(
getInfo
().
getNamespace
()
).
iterator
();
}
@Override
public
IQ
handleIQ
(
IQ
packet
)
throws
UnauthorizedException
{
if
(
packet
.
isResponse
()
)
{
Log
.
debug
(
"Silently ignoring IQ response: {}"
,
packet
);
return
null
;
}
if
(
IQ
.
Type
.
set
==
packet
.
getType
()
)
{
Log
.
info
(
"Responding with an error to an IQ request of type 'set': {}"
,
packet
);
final
IQ
response
=
IQ
.
createResultIQ
(
packet
);
response
.
setError
(
PacketError
.
Condition
.
service_unavailable
);
return
response
;
}
final
IQ
response
;
switch
(
packet
.
getChildElement
().
getName
()
)
{
case
"services"
:
response
=
handleServices
(
packet
);
break
;
case
"credentials"
:
response
=
handleCredentials
(
packet
);
break
;
default
:
Log
.
info
(
"Responding with an error to an IQ request for which the element name escaped by namespace is not understood: {}"
,
packet
);
response
=
IQ
.
createResultIQ
(
packet
);
response
.
setError
(
PacketError
.
Condition
.
service_unavailable
);
}
Log
.
info
(
"Responding with {} to request {}"
,
response
.
toXML
(),
packet
.
toXML
()
);
return
response
;
}
/**
* Handles requests for services.
*
* @param request the request (cannot be null).
* @return An answer (never null).
*/
protected
IQ
handleServices
(
IQ
request
)
{
final
Map
<
Service
,
Credentials
>
services
;
final
ServiceManager
serviceManager
=
ServiceManager
.
getInstance
();
final
String
requestedType
=
request
.
getChildElement
().
attributeValue
(
"type"
);
if
(
requestedType
==
null
||
requestedType
.
isEmpty
()
)
{
Log
.
debug
(
"Handling request for all services."
);
services
=
serviceManager
.
getServicesFor
(
request
.
getFrom
()
);
}
else
{
Log
.
debug
(
"Handling request for services of a specific type: {}."
,
requestedType
);
services
=
serviceManager
.
getServicesFor
(
request
.
getFrom
(),
requestedType
);
}
// Formulate response.
final
IQ
response
=
IQ
.
createResultIQ
(
request
);
final
Element
childElement
=
response
.
setChildElement
(
request
.
getChildElement
().
getName
(),
request
.
getChildElement
().
getNamespaceURI
()
);
if
(
requestedType
!=
null
&&
!
requestedType
.
isEmpty
()
)
{
childElement
.
addAttribute
(
"type"
,
requestedType
);
}
for
(
final
Map
.
Entry
<
Service
,
Credentials
>
entry
:
services
.
entrySet
()
)
{
addServiceXml
(
childElement
,
entry
.
getKey
(),
null
,
entry
.
getValue
()
);
}
return
response
;
}
/**
* Handles requests for credentials
*
* @param request the request (cannot be null).
* @return An answer (never null).
*/
protected
IQ
handleCredentials
(
IQ
request
)
{
final
Element
requestedService
=
request
.
getChildElement
().
element
(
"service"
);
if
(
requestedService
==
null
)
{
Log
.
debug
(
"Responding with an error to a request for credentials that did not specify any service: {}"
,
request
);
final
IQ
response
=
IQ
.
createResultIQ
(
request
);
response
.
setError
(
PacketError
.
Condition
.
bad_request
);
return
response
;
}
final
String
requestedHost
=
requestedService
.
attributeValue
(
"host"
);
final
String
requestedType
=
requestedService
.
attributeValue
(
"type"
);
final
Integer
requestedPort
;
if
(
requestedService
.
attribute
(
"port"
)
!=
null
)
{
try
{
requestedPort
=
Integer
.
parseInt
(
requestedService
.
attributeValue
(
"port"
)
);
}
catch
(
NumberFormatException
ex
)
{
Log
.
debug
(
"Responding with an error to a request for credentials that specified a malformed port number for a service: {}"
,
request
,
ex
);
final
IQ
response
=
IQ
.
createResultIQ
(
request
);
response
.
setError
(
PacketError
.
Condition
.
bad_request
);
return
response
;
}
}
else
{
requestedPort
=
null
;
}
if
(
requestedHost
==
null
||
requestedHost
.
isEmpty
()
||
requestedType
==
null
||
requestedType
.
isEmpty
()
)
{
Log
.
debug
(
"Responding with an error to a request for credentials that did not specify any service: {}"
,
request
);
final
IQ
response
=
IQ
.
createResultIQ
(
request
);
response
.
setError
(
PacketError
.
Condition
.
bad_request
);
return
response
;
}
final
ServiceManager
serviceManager
=
ServiceManager
.
getInstance
();
final
Map
<
Service
,
Credentials
>
services
;
if
(
requestedPort
==
null
)
{
Log
.
debug
(
"Handling request for credentials by {} for the {} service: {}"
,
request
.
getFrom
(),
requestedType
,
requestedHost
);
services
=
serviceManager
.
getServicesFor
(
request
.
getFrom
(),
requestedHost
,
requestedType
);
}
else
{
Log
.
debug
(
"Handling request for credentials by {} for the {} service: {}:{}"
,
request
.
getFrom
(),
requestedType
,
requestedHost
,
requestedPort
);
services
=
serviceManager
.
getServicesFor
(
request
.
getFrom
(),
requestedHost
,
requestedType
,
requestedPort
);
}
// Formulate response.
final
IQ
response
=
IQ
.
createResultIQ
(
request
);
final
Element
childElement
=
response
.
setChildElement
(
"credentials"
,
request
.
getChildElement
().
getNamespaceURI
()
);
for
(
final
Map
.
Entry
<
Service
,
Credentials
>
service
:
services
.
entrySet
()
)
{
addServiceXml
(
childElement
,
service
.
getKey
(),
null
,
service
.
getValue
()
);
}
return
response
;
}
abstract
void
addServiceXml
(
Element
parent
,
Service
service
,
final
Service
.
Action
action
,
final
Credentials
credentials
);
}
src/plugins/externalservicediscovery/src/java/org/igniterealtime/openfire/plugins/externalservicediscovery/ExternalServiceDiscoveryIQHandlerV1.java
0 → 100644
View file @
321c282d
/*
* Copyright (C) 2017 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
igniterealtime
.
openfire
.
plugins
.
externalservicediscovery
;
import
org.dom4j.Element
;
import
org.jivesoftware.openfire.IQHandlerInfo
;
import
org.jivesoftware.openfire.auth.UnauthorizedException
;
import
org.jivesoftware.openfire.disco.ServerFeaturesProvider
;
import
org.jivesoftware.openfire.handler.IQHandler
;
import
org.jivesoftware.util.XMPPDateTimeFormat
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.xmpp.packet.IQ
;
import
org.xmpp.packet.PacketError
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.Iterator
;
import
java.util.Map
;
/**
* An IQ handler that implements XEP-0215: External Service Discovery, Version 0.6 (2014-02-27)
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
* @see <a href="https://xmpp.org/extensions/xep-0215.html">XEP-0215: External Service Discovery</a>
*/
public
class
ExternalServiceDiscoveryIQHandlerV1
extends
ExternalServiceDiscoveryIQHandler
{
private
static
final
Logger
Log
=
LoggerFactory
.
getLogger
(
ExternalServiceDiscoveryIQHandlerV1
.
class
);
private
final
static
IQHandlerInfo
INFO
=
new
IQHandlerInfo
(
"services"
,
"urn:xmpp:extdisco:1"
);
@Override
public
IQHandlerInfo
getInfo
()
{
return
INFO
;
}
@Override
public
void
addServiceXml
(
Element
parent
,
Service
service
,
final
Service
.
Action
action
,
final
Credentials
credentials
)
{
final
Element
result
=
parent
.
addElement
(
"service"
);
if
(
credentials
!=
null
)
{
if
(
credentials
.
getUsername
()
!=
null
)
{
result
.
addAttribute
(
"username"
,
credentials
.
getUsername
()
);
}
if
(
credentials
.
getPassword
()
!=
null
)
{
result
.
addAttribute
(
"password"
,
credentials
.
getPassword
()
);
}
}
if
(
service
.
getHost
()
!=
null
)
{
result
.
addAttribute
(
"host"
,
service
.
getHost
()
);
}
if
(
service
.
getName
()
!=
null
)
{
result
.
addAttribute
(
"name"
,
service
.
getName
()
);
}
if
(
service
.
getPort
()
!=
null
)
{
result
.
addAttribute
(
"port"
,
Integer
.
toString
(
service
.
getPort
()
)
);
}
if
(
service
.
getTransport
()
!=
null
)
{
result
.
addAttribute
(
"transport"
,
service
.
getTransport
()
);
}
if
(
service
.
getType
()
!=
null
)
{
result
.
addAttribute
(
"type"
,
service
.
getType
()
);
}
}
}
src/plugins/externalservicediscovery/src/java/org/igniterealtime/openfire/plugins/externalservicediscovery/ExternalServiceDiscoveryIQHandlerV2.java
0 → 100644
View file @
321c282d
/*
* Copyright (C) 2017 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
igniterealtime
.
openfire
.
plugins
.
externalservicediscovery
;
import
org.dom4j.Element
;
import
org.jivesoftware.openfire.IQHandlerInfo
;
import
org.jivesoftware.openfire.auth.UnauthorizedException
;
import
org.jivesoftware.openfire.disco.ServerFeaturesProvider
;
import
org.jivesoftware.openfire.handler.IQHandler
;
import
org.jivesoftware.util.XMPPDateTimeFormat
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.xmpp.packet.IQ
;
import
org.xmpp.packet.PacketError
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.Iterator
;
import
java.util.Map
;
/**
* An IQ handler that implements XEP-0215: External Service Discovery, Version 0.7 (2015-10-20).
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
* @see <a href="https://xmpp.org/extensions/xep-0215.html">XEP-0215: External Service Discovery</a>
*/
public
class
ExternalServiceDiscoveryIQHandlerV2
extends
ExternalServiceDiscoveryIQHandler
{
private
static
final
Logger
Log
=
LoggerFactory
.
getLogger
(
ExternalServiceDiscoveryIQHandlerV2
.
class
);
private
final
static
IQHandlerInfo
INFO
=
new
IQHandlerInfo
(
"services"
,
"urn:xmpp:extdisco:2"
);
@Override
public
IQHandlerInfo
getInfo
()
{
return
INFO
;
}
@Override
public
void
addServiceXml
(
Element
parent
,
Service
service
,
final
Service
.
Action
action
,
final
Credentials
credentials
)
{
final
Element
result
=
parent
.
addElement
(
"service"
);
if
(
action
!=
null
)
{
result
.
addAttribute
(
"action"
,
action
.
toString
()
);
}
if
(
credentials
!=
null
)
{
if
(
credentials
.
getExpires
()
!=
null
)
{
result
.
addAttribute
(
"expires"
,
XMPPDateTimeFormat
.
format
(
credentials
.
getExpires
()
)
);
}
if
(
credentials
.
getUsername
()
!=
null
)
{
result
.
addAttribute
(
"username"
,
credentials
.
getUsername
()
);
}
if
(
credentials
.
getPassword
()
!=
null
)
{
result
.
addAttribute
(
"password"
,
credentials
.
getPassword
()
);
}
}
if
(
service
.
getHost
()
!=
null
)
{
result
.
addAttribute
(
"host"
,
service
.
getHost
()
);
}
if
(
service
.
getName
()
!=
null
)
{
result
.
addAttribute
(
"name"
,
service
.
getName
()
);
}
if
(
service
.
getPort
()
!=
null
)
{
result
.
addAttribute
(
"port"
,
Integer
.
toString
(
service
.
getPort
()
)
);
}
if
(
service
.
getRestricted
()
!=
null
)
{
result
.
addAttribute
(
"restricted"
,
Boolean
.
toString
(
service
.
getRestricted
()
)
);
}
if
(
service
.
getTransport
()
!=
null
)
{
result
.
addAttribute
(
"transport"
,
service
.
getTransport
()
);
}
if
(
service
.
getType
()
!=
null
)
{
result
.
addAttribute
(
"type"
,
service
.
getType
()
);
}
}
}
src/plugins/externalservicediscovery/src/java/org/igniterealtime/openfire/plugins/externalservicediscovery/ExternalServiceDiscoveryPlugin.java
0 → 100644
View file @
321c282d
/*
* Copyright (C) 2017 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
igniterealtime
.
openfire
.
plugins
.
externalservicediscovery
;
import
org.jivesoftware.openfire.XMPPServer
;
import
org.jivesoftware.openfire.container.Plugin
;
import
org.jivesoftware.openfire.container.PluginManager
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
java.io.File
;
import
java.util.Iterator
;
/**
* An Openfire plugin that implements XEP-0215: External Service Discovery.
*
* This plugin allowS XMPP entities to discover services external to the XMPP network, such as STUN and TURN servers.
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
* @see <a href="https://xmpp.org/extensions/xep-0215.html">XEP-0215: External Service Discovery</a>
*/
public
class
ExternalServiceDiscoveryPlugin
implements
Plugin
{
private
static
final
Logger
Log
=
LoggerFactory
.
getLogger
(
ExternalServiceDiscoveryPlugin
.
class
);
private
ExternalServiceDiscoveryIQHandlerV1
iqHandlerV1
;
private
ExternalServiceDiscoveryIQHandlerV2
iqHandlerV2
;
@Override
public
void
initializePlugin
(
PluginManager
manager
,
File
pluginDirectory
)
{
Log
.
debug
(
"Registering IQ Handlers..."
);
iqHandlerV1
=
new
ExternalServiceDiscoveryIQHandlerV1
();
iqHandlerV2
=
new
ExternalServiceDiscoveryIQHandlerV2
();
XMPPServer
.
getInstance
().
getIQRouter
().
addHandler
(
iqHandlerV1
);
XMPPServer
.
getInstance
().
getIQRouter
().
addHandler
(
iqHandlerV2
);
Log
.
debug
(
"Registering Server Features..."
);
for
(
final
Iterator
<
String
>
it
=
iqHandlerV1
.
getFeatures
();
it
.
hasNext
();
)
{
XMPPServer
.
getInstance
().
getIQDiscoInfoHandler
().
addServerFeature
(
it
.
next
()
);
}
for
(
final
Iterator
<
String
>
it
=
iqHandlerV2
.
getFeatures
();
it
.
hasNext
();
)
{
XMPPServer
.
getInstance
().
getIQDiscoInfoHandler
().
addServerFeature
(
it
.
next
()
);
}
Log
.
debug
(
"Initialized."
);
}
@Override
public
void
destroyPlugin
()
{
Log
.
debug
(
"Removing Server Features..."
);
for
(
final
Iterator
<
String
>
it
=
iqHandlerV2
.
getFeatures
();
it
.
hasNext
();
)
{
XMPPServer
.
getInstance
().
getIQDiscoInfoHandler
().
removeServerFeature
(
it
.
next
()
);
}
for
(
final
Iterator
<
String
>
it
=
iqHandlerV1
.
getFeatures
();
it
.
hasNext
();
)
{
XMPPServer
.
getInstance
().
getIQDiscoInfoHandler
().
removeServerFeature
(
it
.
next
()
);
}
if
(
iqHandlerV2
!=
null
)
{
Log
.
debug
(
"Removing IQ Handler..."
);
XMPPServer
.
getInstance
().
getIQRouter
().
removeHandler
(
iqHandlerV2
);
}
if
(
iqHandlerV1
!=
null
)
{
Log
.
debug
(
"Removing IQ Handler..."
);
XMPPServer
.
getInstance
().
getIQRouter
().
removeHandler
(
iqHandlerV1
);
}
Log
.
debug
(
"Destroyed."
);
}
}
src/plugins/externalservicediscovery/src/java/org/igniterealtime/openfire/plugins/externalservicediscovery/Service.java
0 → 100644
View file @
321c282d
/*
* Copyright (C) 2017 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
igniterealtime
.
openfire
.
plugins
.
externalservicediscovery
;
import
org.jivesoftware.database.JiveID
;
import
org.jivesoftware.database.SequenceManager
;
import
org.jivesoftware.util.StringUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.xmpp.packet.JID
;
import
javax.crypto.Mac
;
import
javax.crypto.spec.SecretKeySpec
;
import
java.io.UnsupportedEncodingException
;
import
java.net.URLEncoder
;
import
java.nio.charset.StandardCharsets
;
import
java.security.InvalidKeyException
;
import
java.security.NoSuchAlgorithmException
;
import
java.util.Date
;
/**
* A representation of a Service object.
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
*/
@JiveID
(
937
)
public
final
class
Service
{
private
final
static
Logger
Log
=
LoggerFactory
.
getLogger
(
Service
.
class
);
private
final
long
databaseId
;
/**
* When sending a push update, the action value indicates if the service is being added or deleted from the set of
* known services (or simply being modified). The defined values are "add", "remove", and "modify", where "add" is
* the default.
*/
enum
Action
{
add
,
remove
,
modify
}
/**
* Either a fully qualified domain name (FQDN) or an IP address (IPv4 or IPv6).
*
* Required.
*/
private
final
String
host
;
/**
* A friendly (human-readable) name or label for the service.
*
* Optional.
*/
private
final
String
name
;
/**
* The communications port to be used at the host.
*
* Recommended.
*/
private
final
Integer
port
;
/**
* A boolean value indicating that username and password credentials are required and will need to be requested if
* not already provided (see Requesting Credentials).
*
* Optional.
*/
private
final
Boolean
restricted
;
/**
* The underlying transport protocol to be used when communicating with the service (typically either TCP or UDP).
*
* Recommended.
*/
private
final
String
transport
;
/**
* The service type as registered with the XMPP Registrar.
*
* Required.
*/
private
final
String
type
;
/**
* The (hard-coded) credentials to use in this service.
*
* Optional.
*/
private
final
Credentials
credentials
;
/**
* A secret shared with the TURN server, used to generate ephemeral credentials.
*
* Optional.
*/
private
final
SecretKeySpec
secretKey
;
public
Service
(
String
name
,
String
host
,
Integer
port
,
String
transport
,
String
type
)
{
if
(
host
==
null
||
host
.
isEmpty
()
)
{
throw
new
IllegalArgumentException
(
"Argument 'host' cannot be null or an empty string."
);
}
if
(
type
==
null
||
type
.
isEmpty
()
)
{
throw
new
IllegalArgumentException
(
"Argument 'type' cannot be null or an empty string."
);
}
this
.
databaseId
=
SequenceManager
.
nextID
(
this
);
this
.
host
=
host
;
this
.
name
=
name
;
this
.
port
=
port
;
this
.
restricted
=
false
;
this
.
transport
=
transport
;
this
.
type
=
type
;
this
.
credentials
=
null
;
this
.
secretKey
=
null
;
}
public
Service
(
String
name
,
String
host
,
Integer
port
,
String
transport
,
String
type
,
String
username
,
String
password
)
{
if
(
host
==
null
||
host
.
isEmpty
()
)
{
throw
new
IllegalArgumentException
(
"Argument 'host' cannot be null or an empty string."
);
}
if
(
type
==
null
||
type
.
isEmpty
()
)
{
throw
new
IllegalArgumentException
(
"Argument 'type' cannot be null or an empty string."
);
}
this
.
databaseId
=
SequenceManager
.
nextID
(
this
);
this
.
host
=
host
;
this
.
name
=
name
;
this
.
port
=
port
;
this
.
restricted
=
true
;
// technically, could be false, but that'll probably be confusing more than a feature.
this
.
transport
=
transport
;
this
.
type
=
type
;
this
.
credentials
=
new
Credentials
(
username
,
password
,
null
);
this
.
secretKey
=
null
;
}
public
Service
(
String
name
,
String
host
,
Integer
port
,
String
transport
,
String
type
,
String
sharedSecret
)
{
if
(
host
==
null
||
host
.
isEmpty
()
)
{
throw
new
IllegalArgumentException
(
"Argument 'host' cannot be null or an empty string."
);
}
if
(
type
==
null
||
type
.
isEmpty
()
)
{
throw
new
IllegalArgumentException
(
"Argument 'type' cannot be null or an empty string."
);
}
this
.
databaseId
=
SequenceManager
.
nextID
(
this
);
this
.
host
=
host
;
this
.
name
=
name
;
this
.
port
=
port
;
this
.
restricted
=
true
;
// technically, could be false, but that'll probably be confusing more than a feature.
this
.
transport
=
transport
;
this
.
type
=
type
;
this
.
credentials
=
null
;
if
(
sharedSecret
==
null
||
sharedSecret
.
isEmpty
()
)
{
this
.
secretKey
=
null
;
}
else
{
this
.
secretKey
=
new
SecretKeySpec
(
sharedSecret
.
getBytes
(
StandardCharsets
.
UTF_8
),
"HmacSHA1"
);
}
}
Service
(
long
databaseId
,
String
name
,
String
host
,
Integer
port
,
Boolean
restricted
,
String
transport
,
String
type
,
String
username
,
String
password
,
String
sharedSecret
)
{
if
(
host
==
null
||
host
.
isEmpty
()
)
{
throw
new
IllegalArgumentException
(
"Argument 'host' cannot be null or an empty string."
);
}
if
(
type
==
null
||
type
.
isEmpty
()
)
{
throw
new
IllegalArgumentException
(
"Argument 'type' cannot be null or an empty string."
);
}
this
.
databaseId
=
databaseId
;
this
.
host
=
host
;
this
.
name
=
name
;
this
.
port
=
port
;
this
.
restricted
=
restricted
;
this
.
transport
=
transport
;
this
.
type
=
type
;
if
(
username
==
null
&&
password
==
null
)
{
this
.
credentials
=
null
;
}
else
{
this
.
credentials
=
new
Credentials
(
username
,
password
,
null
);
}
if
(
sharedSecret
==
null
)
{
this
.
secretKey
=
null
;
}
else
{
this
.
secretKey
=
new
SecretKeySpec
(
sharedSecret
.
getBytes
(
StandardCharsets
.
UTF_8
),
"HmacSHA1"
);
}
}
public
long
getDatabaseId
()
{
return
databaseId
;
}
public
String
getHost
()
{
return
host
;
}
public
String
getName
()
{
return
name
;
}
public
Integer
getPort
()
{
return
port
;
}
public
Boolean
getRestricted
()
{
return
restricted
;
}
public
String
getTransport
()
{
return
transport
;
}
public
String
getType
()
{
return
type
;
}
public
String
getSharedSecret
()
{
if
(
secretKey
==
null
)
{
return
null
;
}
return
new
String
(
secretKey
.
getEncoded
(),
StandardCharsets
.
UTF_8
);
}
public
String
getRawUsername
()
{
if
(
credentials
==
null
)
{
return
null
;
}
return
credentials
.
getUsername
();
}
String
getRawPassword
()
{
if
(
credentials
==
null
)
{
return
null
;
}
return
credentials
.
getPassword
();
}
public
Credentials
getCredentialsFor
(
JID
user
)
{
if
(
credentials
!=
null
)
{
return
credentials
;
}
if
(
secretKey
!=
null
)
{
final
int
ttl
=
86400
;
final
Date
expires
=
new
Date
(
System
.
currentTimeMillis
()
+
(
ttl
*
1000
)
);
final
String
asSecondsSinceEpoch
=
Long
.
toString
(
expires
.
getTime
()
/
1000
);
// temporary-username="timestamp" + ":" + "username"
String
username
=
asSecondsSinceEpoch
;
// The TURN server should accept usernames without an identifier-part.
if
(
user
!=
null
)
{
// Try to set the JID as a username part, if we can.
try
{
// Although RFC 5389 appears to allow for unescaped JIDs to be used as TURN usernames, problems have
// been reported (eg: https://github.com/versatica/JsSIP/issues/184)111
username
=
URLEncoder
.
encode
(
user
.
toBareJID
(),
"ASCII"
)
+
":"
+
asSecondsSinceEpoch
;
}
catch
(
UnsupportedEncodingException
e
)
{
Log
.
debug
(
"Unable to encode JID ''."
,
user
.
toBareJID
(),
e
);
}
}
// temporary-password = base64_encode(hmac-sha1(input = temporary-username, key = shared-secret))
final
String
password
;
try
{
final
Mac
mac
=
Mac
.
getInstance
(
"HmacSHA1"
);
mac
.
init
(
secretKey
);
final
byte
[]
nonce
=
mac
.
doFinal
(
username
.
getBytes
(
StandardCharsets
.
UTF_8
)
);
password
=
StringUtils
.
encodeBase64
(
nonce
);
}
catch
(
InvalidKeyException
|
NoSuchAlgorithmException
e
)
{
Log
.
warn
(
"Unable to create ephemeral credentials for '{}' on {}:{}"
,
user
,
host
,
port
,
e
);
return
null
;
}
return
new
Credentials
(
username
,
password
,
expires
);
}
return
null
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
{
return
true
;
}
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
()
)
{
return
false
;
}
final
Service
service
=
(
Service
)
o
;
if
(
databaseId
!=
service
.
databaseId
)
{
return
false
;
}
if
(
!
host
.
equals
(
service
.
host
)
)
{
return
false
;
}
if
(
name
!=
null
?
!
name
.
equals
(
service
.
name
)
:
service
.
name
!=
null
)
{
return
false
;
}
if
(
port
!=
null
?
!
port
.
equals
(
service
.
port
)
:
service
.
port
!=
null
)
{
return
false
;
}
if
(
restricted
!=
null
?
!
restricted
.
equals
(
service
.
restricted
)
:
service
.
restricted
!=
null
)
{
return
false
;
}
if
(
transport
!=
null
?
!
transport
.
equals
(
service
.
transport
)
:
service
.
transport
!=
null
)
{
return
false
;
}
if
(
!
type
.
equals
(
service
.
type
)
)
{
return
false
;
}
if
(
credentials
!=
null
?
!
credentials
.
equals
(
service
.
credentials
)
:
service
.
credentials
!=
null
)
{
return
false
;
}
return
secretKey
!=
null
?
secretKey
.
equals
(
service
.
secretKey
)
:
service
.
secretKey
==
null
;
}
@Override
public
int
hashCode
()
{
int
result
=
(
int
)
(
databaseId
^
(
databaseId
>>>
32
)
);
result
=
31
*
result
+
host
.
hashCode
();
result
=
31
*
result
+
(
name
!=
null
?
name
.
hashCode
()
:
0
);
result
=
31
*
result
+
(
port
!=
null
?
port
.
hashCode
()
:
0
);
result
=
31
*
result
+
(
restricted
!=
null
?
restricted
.
hashCode
()
:
0
);
result
=
31
*
result
+
(
transport
!=
null
?
transport
.
hashCode
()
:
0
);
result
=
31
*
result
+
type
.
hashCode
();
result
=
31
*
result
+
(
credentials
!=
null
?
credentials
.
hashCode
()
:
0
);
result
=
31
*
result
+
(
secretKey
!=
null
?
secretKey
.
hashCode
()
:
0
);
return
result
;
}
}
src/plugins/externalservicediscovery/src/java/org/igniterealtime/openfire/plugins/externalservicediscovery/ServiceManager.java
0 → 100644
View file @
321c282d
/*
* Copyright (C) 2017 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
igniterealtime
.
openfire
.
plugins
.
externalservicediscovery
;
import
org.jivesoftware.database.DbConnectionManager
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.xmpp.packet.JID
;
import
java.sql.Connection
;
import
java.sql.PreparedStatement
;
import
java.sql.ResultSet
;
import
java.sql.Types
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Set
;
/**
* A manager of {@link Service} instances.
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
*/
public
class
ServiceManager
{
private
static
final
Logger
Log
=
LoggerFactory
.
getLogger
(
ServiceManager
.
class
);
private
Set
<
Service
>
services
=
new
HashSet
<>();
// Not making this a singleton, to allow for database-reloads in a cluster.
public
static
ServiceManager
getInstance
()
{
final
ServiceManager
instance
=
new
ServiceManager
();
Connection
con
=
null
;
PreparedStatement
pstmt
=
null
;
ResultSet
resultSet
=
null
;
try
{
con
=
DbConnectionManager
.
getConnection
();
pstmt
=
con
.
prepareStatement
(
"SELECT * FROM ofExternalServices "
);
resultSet
=
pstmt
.
executeQuery
();
while
(
resultSet
.
next
()
)
{
final
long
databaseId
=
resultSet
.
getLong
(
"serviceID"
);
String
name
=
resultSet
.
getString
(
"name"
);
if
(
resultSet
.
wasNull
()
||
name
==
null
||
name
.
isEmpty
()
)
{
name
=
null
;
}
String
host
=
resultSet
.
getString
(
"host"
);
if
(
resultSet
.
wasNull
()
||
host
==
null
||
host
.
isEmpty
()
)
{
host
=
null
;
}
Integer
port
=
resultSet
.
getInt
(
"port"
);
if
(
resultSet
.
wasNull
()
)
{
port
=
null
;
}
Boolean
restricted
=
resultSet
.
getBoolean
(
"restricted"
);
if
(
resultSet
.
wasNull
()
)
{
restricted
=
null
;
}
String
transport
=
resultSet
.
getString
(
"transport"
);
if
(
resultSet
.
wasNull
()
||
transport
==
null
||
transport
.
isEmpty
()
)
{
transport
=
null
;
}
String
type
=
resultSet
.
getString
(
"type"
);
if
(
resultSet
.
wasNull
()
||
type
==
null
||
type
.
isEmpty
()
)
{
type
=
null
;
}
String
username
=
resultSet
.
getString
(
"username"
);
if
(
resultSet
.
wasNull
()
||
username
==
null
||
username
.
isEmpty
()
)
{
username
=
null
;
}
String
password
=
resultSet
.
getString
(
"password"
);
if
(
resultSet
.
wasNull
()
||
password
==
null
||
password
.
isEmpty
()
)
{
password
=
null
;
}
String
sharedSecret
=
resultSet
.
getString
(
"sharedSecret"
);
if
(
resultSet
.
wasNull
()
||
sharedSecret
==
null
||
sharedSecret
.
isEmpty
()
)
{
sharedSecret
=
null
;
}
final
Service
service
=
new
Service
(
databaseId
,
name
,
host
,
port
,
restricted
,
transport
,
type
,
username
,
password
,
sharedSecret
);
instance
.
services
.
add
(
service
);
Log
.
debug
(
"Loaded {} service at {} from database."
,
service
.
getType
(),
service
.
getHost
()
);
}
}
catch
(
Exception
e
)
{
Log
.
error
(
"Unable to load services from database!"
,
e
);
}
finally
{
DbConnectionManager
.
closeConnection
(
resultSet
,
pstmt
,
con
);
}
return
instance
;
}
public
void
addService
(
Service
service
)
{
if
(
services
.
add
(
service
)
)
{
Connection
con
=
null
;
PreparedStatement
pstmt
=
null
;
try
{
con
=
DbConnectionManager
.
getConnection
();
pstmt
=
con
.
prepareStatement
(
"INSERT INTO ofExternalServices VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
);
pstmt
.
setLong
(
1
,
service
.
getDatabaseId
()
);
if
(
service
.
getName
()
==
null
||
service
.
getName
().
isEmpty
()
)
{
pstmt
.
setNull
(
2
,
Types
.
VARCHAR
);
}
else
{
pstmt
.
setString
(
2
,
service
.
getName
()
);
}
if
(
service
.
getHost
()
==
null
||
service
.
getHost
().
isEmpty
()
)
{
pstmt
.
setNull
(
3
,
Types
.
VARCHAR
);
}
else
{
pstmt
.
setString
(
3
,
service
.
getHost
()
);
}
if
(
service
.
getPort
()
==
null
)
{
pstmt
.
setNull
(
4
,
Types
.
INTEGER
);
}
else
{
pstmt
.
setInt
(
4
,
service
.
getPort
()
);
}
if
(
service
.
getRestricted
()
==
null
)
{
pstmt
.
setNull
(
5
,
Types
.
BOOLEAN
);
}
else
{
pstmt
.
setBoolean
(
5
,
service
.
getRestricted
()
);
}
if
(
service
.
getTransport
()
==
null
||
service
.
getTransport
().
isEmpty
()
)
{
pstmt
.
setNull
(
6
,
Types
.
CHAR
);
}
else
{
pstmt
.
setString
(
6
,
service
.
getTransport
()
);
}
if
(
service
.
getType
()
==
null
||
service
.
getType
().
isEmpty
()
)
{
pstmt
.
setNull
(
7
,
Types
.
CHAR
);
}
else
{
pstmt
.
setString
(
7
,
service
.
getType
()
);
}
if
(
service
.
getRawUsername
()
==
null
||
service
.
getRawUsername
().
isEmpty
()
)
{
pstmt
.
setNull
(
8
,
Types
.
VARCHAR
);
}
else
{
pstmt
.
setString
(
8
,
service
.
getRawUsername
()
);
}
if
(
service
.
getRawPassword
()
==
null
||
service
.
getRawPassword
().
isEmpty
()
)
{
pstmt
.
setNull
(
9
,
Types
.
VARCHAR
);
}
else
{
pstmt
.
setString
(
9
,
service
.
getRawPassword
()
);
}
if
(
service
.
getSharedSecret
()
==
null
||
service
.
getSharedSecret
().
isEmpty
()
)
{
pstmt
.
setNull
(
10
,
Types
.
VARCHAR
);
}
else
{
pstmt
.
setString
(
10
,
service
.
getSharedSecret
()
);
}
pstmt
.
executeUpdate
();
Log
.
info
(
"Added {} service at {}."
,
service
.
getType
(),
service
.
getHost
()
);
}
catch
(
Exception
e
)
{
Log
.
error
(
"Unable to persists service ({} at {}) in database!"
,
service
.
getType
(),
service
.
getHost
(),
e
);
services
.
remove
(
service
);
}
finally
{
DbConnectionManager
.
closeConnection
(
pstmt
,
con
);
}
}
}
public
void
removeService
(
Service
service
)
{
Connection
con
=
null
;
PreparedStatement
pstmt
=
null
;
try
{
con
=
DbConnectionManager
.
getConnection
();
pstmt
=
con
.
prepareStatement
(
"DELETE FROM ofExternalServices WHERE serviceID=?"
);
pstmt
.
setLong
(
1
,
service
.
getDatabaseId
()
);
if
(
pstmt
.
executeUpdate
()
==
0
)
{
Log
.
warn
(
"The query to remove {} service at {} from the database did not remove anything."
,
service
.
getType
(),
service
.
getHost
()
);
}
else
{
services
.
remove
(
service
);
Log
.
info
(
"Removed {} service at {}."
,
service
.
getType
(),
service
.
getHost
()
);
}
}
catch
(
Exception
e
)
{
Log
.
error
(
"Unable to remove service ({} at {}) from database!"
,
service
.
getType
(),
service
.
getHost
(),
e
);
}
finally
{
DbConnectionManager
.
closeConnection
(
pstmt
,
con
);
}
}
public
Set
<
Service
>
getAllServices
()
{
return
new
HashSet
<>(
services
);
}
public
Map
<
Service
,
Credentials
>
getServicesFor
(
JID
requester
)
{
Log
.
debug
(
"Obtaining credentials for {}"
,
requester
);
final
Map
<
Service
,
Credentials
>
result
=
new
HashMap
<>();
for
(
final
Service
service
:
services
)
{
try
{
final
Credentials
credentials
=
service
.
getCredentialsFor
(
requester
);
result
.
put
(
service
,
credentials
);
}
catch
(
Exception
e
)
{
Log
.
warn
(
"Unable to obtain credentials for requester '{}', for the {} service at: {}"
,
requester
,
service
.
getType
(),
service
.
getHost
(),
e
);
}
}
return
result
;
}
public
Map
<
Service
,
Credentials
>
getServicesFor
(
JID
requester
,
String
requestedType
)
{
Log
.
debug
(
"Obtaining credentials for {} of type {}"
,
requester
,
requestedType
);
final
Map
<
Service
,
Credentials
>
result
=
new
HashMap
<>();
for
(
final
Service
service
:
services
)
{
if
(
requestedType
.
equals
(
service
.
getType
()
)
)
{
try
{
final
Credentials
credentials
=
service
.
getCredentialsFor
(
requester
);
result
.
put
(
service
,
credentials
);
}
catch
(
Exception
e
)
{
Log
.
warn
(
"Unable to obtain credentials for requester '{}', for the {} service at: {}"
,
requester
,
service
.
getType
(),
service
.
getHost
(),
e
);
}
}
}
return
result
;
}
public
Map
<
Service
,
Credentials
>
getServicesFor
(
JID
requester
,
String
requestedHost
,
String
requestedType
)
{
Log
.
debug
(
"Obtaining credentials for {} on {} of type {}"
,
requester
,
requestedHost
,
requestedType
);
final
Map
<
Service
,
Credentials
>
result
=
new
HashMap
<>();
for
(
final
Service
service
:
services
)
{
if
(
requestedType
.
equals
(
service
.
getType
()
)
&&
requestedHost
.
equals
(
service
.
getHost
()
)
)
{
try
{
final
Credentials
credentials
=
service
.
getCredentialsFor
(
requester
);
result
.
put
(
service
,
credentials
);
}
catch
(
Exception
e
)
{
Log
.
warn
(
"Unable to obtain credentials for requester '{}', for the {} service at: {}"
,
requester
,
service
.
getType
(),
service
.
getHost
(),
e
);
}
}
}
return
result
;
}
public
Map
<
Service
,
Credentials
>
getServicesFor
(
JID
requester
,
String
requestedHost
,
String
requestedType
,
int
requestedPort
)
{
Log
.
debug
(
"Obtaining credentials for {} on {}:{} of type {}"
,
requester
,
requestedHost
,
requestedPort
,
requestedType
);
final
Map
<
Service
,
Credentials
>
result
=
new
HashMap
<>();
for
(
final
Service
service
:
services
)
{
if
(
requestedType
.
equals
(
service
.
getType
()
)
&&
requestedHost
.
equals
(
service
.
getHost
()
)
&&
requestedPort
==
service
.
getPort
()
)
{
try
{
final
Credentials
credentials
=
service
.
getCredentialsFor
(
requester
);
result
.
put
(
service
,
credentials
);
}
catch
(
Exception
e
)
{
Log
.
warn
(
"Unable to obtain credentials for requester '{}', for the {} service at: {}:{}"
,
requester
,
requestedType
,
requestedHost
,
requestedPort
,
e
);
}
}
}
return
result
;
}
}
src/plugins/externalservicediscovery/src/test/org/igniterealtime/openfire/plugins/externalservicediscovery/ServiceTest.java
0 → 100644
View file @
321c282d
package
org
.
igniterealtime
.
openfire
.
plugins
.
externalservicediscovery
;
import
nl.jqno.equalsverifier.EqualsVerifier
;
import
org.junit.Test
;
/**
* Simple tests that verify the implementation of {@link Service}.
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
*/
public
class
ServiceTest
{
/**
* Happy flow - should not cause any issues.
*/
@Test
public
void
testPackageConstructor
()
{
int
databaseId
=
-
1
;
String
name
=
"description"
;
String
host
=
"host"
;
Integer
port
=
123
;
Boolean
restricted
=
false
;
String
transport
=
"udp"
;
String
type
=
"turn"
;
String
username
=
"username"
;
String
password
=
"password"
;
String
sharedSecret
=
"secret"
;
new
Service
(
databaseId
,
name
,
host
,
port
,
restricted
,
transport
,
type
,
username
,
password
,
sharedSecret
);
}
/**
* Verifies that an IllegalArgumentException is thrown by the constructor when the provided 'host' argument value is null.
*/
@Test
(
expected
=
IllegalArgumentException
.
class
)
public
void
testNullHost
()
{
int
databaseId
=
-
1
;
String
name
=
"description"
;
String
host
=
null
;
Integer
port
=
123
;
Boolean
restricted
=
false
;
String
transport
=
"udp"
;
String
type
=
"turn"
;
String
username
=
"username"
;
String
password
=
"password"
;
String
sharedSecret
=
"secret"
;
new
Service
(
databaseId
,
name
,
host
,
port
,
restricted
,
transport
,
type
,
username
,
password
,
sharedSecret
);
}
/**
* Verifies that an IllegalArgumentException is thrown by the constructor when the provided 'type' argument value is null.
*/
@Test
(
expected
=
IllegalArgumentException
.
class
)
public
void
testNullType
()
{
int
databaseId
=
-
1
;
String
name
=
"description"
;
String
host
=
"host"
;
Integer
port
=
123
;
Boolean
restricted
=
false
;
String
transport
=
"udp"
;
String
type
=
null
;
String
username
=
"username"
;
String
password
=
"password"
;
String
sharedSecret
=
"secret"
;
new
Service
(
databaseId
,
name
,
host
,
port
,
restricted
,
transport
,
type
,
username
,
password
,
sharedSecret
);
}
/**
* Verifies that the implementation adheres to the contract specified in {@link Object#equals(Object)}.
*/
@Test
public
void
equalsContract
()
{
EqualsVerifier
.
forClass
(
Service
.
class
)
.
withNonnullFields
(
"host"
,
"type"
)
// checked by constructor.
.
verify
();
}
}
src/plugins/externalservicediscovery/src/web/WEB-INF/web.xml
0 → 100644
View file @
321c282d
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns=
"http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version=
"3.1"
>
</web-app>
src/plugins/externalservicediscovery/src/web/external-service-discovery-config.jsp
0 → 100644
View file @
321c282d
<!--
- Copyright (C) 2017 Ignite Realtime Foundation. All rights reserved.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-->
<%@ page
errorPage=
"error.jsp"
%>
<%@ page
import=
"org.igniterealtime.openfire.plugins.externalservicediscovery.Service"
%>
<%@ page
import=
"org.igniterealtime.openfire.plugins.externalservicediscovery.ServiceManager"
%>
<%@ page
import=
"org.jivesoftware.util.CookieUtils"
%>
<%@ page
import=
"org.jivesoftware.util.ParamUtils"
%>
<%@ page
import=
"org.jivesoftware.util.StringUtils"
%>
<%@ page
import=
"java.io.UnsupportedEncodingException"
%>
<%@ page
import=
"java.net.URLDecoder"
%>
<%@ page
import=
"java.util.HashMap"
%>
<%@ page
import=
"java.util.Map"
%>
<%@ page
import=
"org.jivesoftware.database.SequenceManager"
%>
<%@ taglib
uri=
"http://java.sun.com/jsp/jstl/core"
prefix=
"c"
%>
<%@ taglib
uri=
"http://java.sun.com/jsp/jstl/fmt"
prefix=
"fmt"
%>
<%@ taglib
uri=
"admin"
prefix=
"admin"
%>
<jsp:useBean
id=
"webManager"
class=
"org.jivesoftware.util.WebManager"
/>
<%
webManager
.
init
(
request
,
response
,
session
,
application
,
out
);
%>
<%!
public
String
getDecodedParameter
(
HttpServletRequest
request
,
String
name
)
throws
UnsupportedEncodingException
{
String
value
=
request
.
getParameter
(
name
);
if
(
value
!=
null
)
{
return
URLDecoder
.
decode
(
value
.
trim
(),
"UTF-8"
);
}
else
{
return
null
;
}
}
%>
<%
String
deleteService
=
getDecodedParameter
(
request
,
"deleteService"
);
String
addService
=
getDecodedParameter
(
request
,
"addService"
);
String
name
=
getDecodedParameter
(
request
,
"name"
);
String
host
=
getDecodedParameter
(
request
,
"host"
);
String
port
=
getDecodedParameter
(
request
,
"port"
);
String
transport
=
getDecodedParameter
(
request
,
"transport"
);
String
type
=
getDecodedParameter
(
request
,
"type"
);
String
credentials
=
getDecodedParameter
(
request
,
"credentials"
);
String
username
=
getDecodedParameter
(
request
,
"username"
);
String
password
=
getDecodedParameter
(
request
,
"password"
);
String
secret
=
getDecodedParameter
(
request
,
"secret"
);
Map
<
String
,
String
>
errors
=
new
HashMap
<
>
();
final
Cookie
csrfCookie
=
CookieUtils
.
getCookie
(
request
,
"csrf"
);
String
csrfParam
=
ParamUtils
.
getParameter
(
request
,
"csrf"
);
if
(
deleteService
!=
null
||
addService
!=
null
)
{
if
(
csrfCookie
==
null
||
csrfParam
==
null
||
!
csrfCookie
.
getValue
().
equals
(
csrfParam
))
{
deleteService
=
null
;
addService
=
null
;
errors
.
put
(
"csrf"
,
"Invalid CSRF value. Reload the page and try again."
);
}
}
csrfParam
=
StringUtils
.
randomString
(
15
);
CookieUtils
.
setCookie
(
request
,
response
,
"csrf"
,
csrfParam
,
-
1
);
pageContext
.
setAttribute
(
"csrf"
,
csrfParam
);
if
(
errors
.
isEmpty
()
)
{
if
(
addService
!=
null
)
{
if
(
host
==
null
||
host
.
isEmpty
()
)
{
errors
.
put
(
"host"
,
"empty"
);
}
if
(
type
==
null
||
type
.
isEmpty
()
)
{
errors
.
put
(
"type"
,
"empty"
);
}
Integer
portValue
=
null
;
if
(
port
!=
null
&&
!
port
.
isEmpty
()
)
{
try
{
portValue
=
Integer
.
parseInt
(
port
);
}
catch
(
NumberFormatException
e
)
{
errors
.
put
(
"port"
,
"not a number"
);
}
}
if
(
"userpass"
.
equals
(
credentials
)
)
{
if
(
username
==
null
||
username
.
isEmpty
()
)
{
errors
.
put
(
"username"
,
"empty"
);
}
if
(
password
==
null
||
password
.
isEmpty
()
)
{
errors
.
put
(
"password"
,
"empty"
);
}
}
if
(
"sharedsecret"
.
equals
(
credentials
)
)
{
if
(
secret
==
null
||
secret
.
isEmpty
()
)
{
errors
.
put
(
"sharedsecret"
,
"empty"
);
}
}
if
(
errors
.
isEmpty
()
)
{
final
Service
service
;
if
(
"userpass"
.
equals
(
credentials
)
)
{
service
=
new
Service
(
name
,
host
,
portValue
,
transport
,
type
,
username
,
password
);
}
else
if
(
"sharedsecret"
.
equals
(
credentials
)
)
{
service
=
new
Service
(
name
,
host
,
portValue
,
transport
,
type
,
secret
);
}
else
{
service
=
new
Service
(
name
,
host
,
portValue
,
transport
,
type
);
}
ServiceManager
.
getInstance
().
addService
(
service
);
response
.
sendRedirect
(
"external-service-discovery-config.jsp?success=addService"
);
return
;
}
}
if
(
deleteService
!=
null
)
{
for
(
final
Service
service
:
ServiceManager
.
getInstance
().
getAllServices
()
)
{
if
(
Long
.
toString
(
service
.
getDatabaseId
()
).
equals
(
deleteService
)
)
{
ServiceManager
.
getInstance
().
removeService
(
service
);
response
.
sendRedirect
(
"external-service-discovery-config.jsp?success=deleteService"
);
return
;
}
}
}
}
pageContext
.
setAttribute
(
"errors"
,
errors
);
pageContext
.
setAttribute
(
"services"
,
ServiceManager
.
getInstance
().
getAllServices
()
);
%>
<html>
<head>
<title><fmt:message
key=
"external-service-discovery-config.title"
/></title>
<meta
name=
"pageID"
content=
"external-service-discovery-config"
/>
<script>
function
check
(
id
)
{
document
.
getElementById
(
'
nocredentials
'
).
checked
=
(
id
===
'
nocredentials
'
);
document
.
getElementById
(
'
userpass
'
).
checked
=
(
id
===
'
userpass
'
);
document
.
getElementById
(
'
sharedsecret
'
).
checked
=
(
id
===
'
sharedsecret
'
);
}
</script>
</head>
<body>
<c:forEach
var=
"err"
items=
"
${
errors
}
"
>
<admin:infobox
type=
"error"
>
<c:choose>
<c:when
test=
"
${
err
.
key
eq
'csrf'
}
"
>
<fmt:message
key=
"global.csrf.failed"
/>
</c:when>
<c:when
test=
"
${
err
.
key
eq
'host'
}
"
>
<fmt:message
key=
"external-service-discovery-config.host-required"
/>
</c:when>
<c:when
test=
"
${
err
.
key
eq
'type'
}
"
>
<fmt:message
key=
"external-service-discovery-config.type-required"
/>
</c:when>
<c:when
test=
"
${
err
.
key
eq
'port'
}
"
>
<fmt:message
key=
"external-service-discovery-config.port-number"
/>
</c:when>
<c:when
test=
"
${
err
.
key
eq
'username'
}
"
>
<fmt:message
key=
"external-service-discovery-config.credentials.username-required"
/>
</c:when>
<c:when
test=
"
${
err
.
key
eq
'password'
}
"
>
<fmt:message
key=
"external-service-discovery-config.credentials.password-required"
/>
</c:when>
<c:when
test=
"
${
err
.
key
eq
'sharedsecret'
}
"
>
<fmt:message
key=
"external-service-discovery-config.credentials.sharedsecret-required"
/>
</c:when>
<c:otherwise>
<c:if
test=
"
${
not
empty
err
.
value
}
"
>
<fmt:message
key=
"admin.error"
/>
:
<c:out
value=
"
${
err
.
value
}
"
/>
</c:if>
(
<c:out
value=
"
${
err
.
key
}
"
/>
)
</c:otherwise>
</c:choose>
</admin:infobox>
</c:forEach>
<!-- Display success report, but only if there were no errors. -->
<c:if
test=
"
${
not
empty
param
[
'success'
]
and
empty
errors
}
"
>
<admin:infoBox
type=
"success"
>
<c:choose>
<c:when
test=
"
${
param
[
'success'
]
eq
'deleteService'
}
"
>
<fmt:message
key=
"external-service-discovery-config.success-delete"
/>
</c:when>
<c:when
test=
"
${
param
[
'success'
]
eq
'addService'
}
"
>
<fmt:message
key=
"external-service-discovery-config.success-add"
/>
</c:when>
</c:choose>
</admin:infoBox>
</c:if>
<p>
<fmt:message
key=
"external-service-discovery-config.descr"
/>
</p>
<div
class=
"jive-table"
>
<table
cellpadding=
"0"
cellspacing=
"0"
border=
"0"
width=
"100%"
>
<thead>
<tr>
<th>
</th>
<th
nowrap
><fmt:message
key=
"external-service-discovery-config.host"
/></th>
<th
nowrap
><fmt:message
key=
"external-service-discovery-config.port"
/></th>
<th
nowrap
><fmt:message
key=
"external-service-discovery-config.name"
/></th>
<th
nowrap
><fmt:message
key=
"external-service-discovery-config.transport"
/></th>
<th
nowrap
><fmt:message
key=
"external-service-discovery-config.type"
/></th>
<th
nowrap
><fmt:message
key=
"external-service-discovery-config.credentials"
/></th>
<th>
</th>
</tr>
</thead>
<tbody>
<c:choose>
<c:when
test=
"
${
empty
services
}
"
>
<tr>
<td
align=
"center"
colspan=
"7"
><fmt:message
key=
"external-service-discovery-config.table.empty"
/></td>
</tr>
</c:when>
<c:otherwise>
<c:forEach
var=
"service"
items=
"
${
services
}
"
>
<tr>
<td>
</td>
<td><c:out
value=
"
${
service
.
host
}
"
/></td>
<td><c:out
value=
"
${
service
.
port
}
"
/></td>
<td><c:out
value=
"
${
service
.
name
}
"
/></td>
<td><c:out
value=
"
${
service
.
transport
}
"
/></td>
<td><c:out
value=
"
${
service
.
type
}
"
/></td>
<td>
<c:choose>
<c:when
test=
"
${
not
empty
service
.
rawUsername
}
"
>
<fmt:message
key=
"external-service-discovery-config.credentials.using-userpass"
/>
<c:out
value=
"service.rawUsername"
/>
</c:when>
<c:when
test=
"
${
not
empty
service
.
sharedSecret
}
"
>
<fmt:message
key=
"external-service-discovery-config.credentials.using-sharedsecret"
/>
</c:when>
<c:otherwise>
<fmt:message
key=
"external-service-discovery-config.credentials.using-nocredentials"
/>
</c:otherwise>
</c:choose>
</td>
<td
width=
"1%"
align=
"center"
>
<a
href=
"external-service-discovery-config.jsp?deleteService=${service.databaseId}&csrf=${csrf}"
title=
"
<fmt:message
key=
"global.click_delete"
/>
"
><img
src=
"images/delete-16x16.gif"
width=
"16"
height=
"16"
border=
"0"
alt=
"
<fmt:message
key=
"global.click_delete"
/>
"
></a>
</td>
</tr>
</c:forEach>
</c:otherwise>
</c:choose>
</tbody>
</table>
</div>
<br/>
<p><fmt:message
key=
"external-service-discovery-config.add-service.descr"
/></p>
<form
action=
"external-service-discovery-config.jsp"
>
<fmt:message
key=
"external-service-discovery-config.add-service.title"
var=
"add_title"
/>
<admin:contentBox
title=
"
${
add_title
}
"
>
<input
type=
"hidden"
name=
"csrf"
value=
"${csrf}"
>
<table
cellpadding=
"0"
cellspacing=
"0"
border=
"0"
>
<tr>
<td
nowrap
><fmt:message
key=
"external-service-discovery-config.host"
/>
*:
</td>
<td><input
type=
"text"
id=
"host"
name=
"host"
size=
"50"
maxlength=
"255"
></td>
</tr>
<tr>
<td
nowrap
><fmt:message
key=
"external-service-discovery-config.port"
/>
:
</td>
<td><input
type=
"text"
id=
"port"
name=
"port"
size=
"7"
maxlength=
"5"
></td>
</tr>
<tr>
<td
nowrap
><fmt:message
key=
"external-service-discovery-config.name"
/>
:
</td>
<td><input
type=
"text"
id=
"name"
name=
"name"
size=
"75"
maxlength=
"255"
></td>
</tr>
<tr>
<td
nowrap
><fmt:message
key=
"external-service-discovery-config.transport"
/>
:
</td>
<td>
<input
type=
"radio"
id=
"tcp"
name=
"transport"
value=
"tcp"
><label
for=
"tcp"
><fmt:message
key=
"external-service-discovery-config.tcp"
/></label>
</td>
</tr>
<tr>
<td
nowrap
>
</td>
<td>
<input
type=
"radio"
id=
"udp"
name=
"transport"
value=
"tcp"
><label
for=
"udp"
><fmt:message
key=
"external-service-discovery-config.udp"
/></label>
</td>
</tr>
<tr>
<td
nowrap
><fmt:message
key=
"external-service-discovery-config.type"
/>
*:
</td>
<td>
<input
type=
"radio"
id=
"stun"
name=
"type"
value=
"stun"
><label
for=
"stun"
><fmt:message
key=
"external-service-discovery-config.stun"
/></label>
</td>
</tr>
<tr>
<td
nowrap
>
</td>
<td>
<input
type=
"radio"
id=
"turn"
name=
"type"
value=
"turn"
><label
for=
"turn"
><fmt:message
key=
"external-service-discovery-config.turn"
/></label>
</td>
</tr>
<tr>
<td
nowrap
>
</td>
<td>
<input
type=
"radio"
id=
"turns"
name=
"type"
value=
"turns"
><label
for=
"turns"
><fmt:message
key=
"external-service-discovery-config.turns"
/></label>
</td>
</tr>
<tr>
<td><fmt:message
key=
"external-service-discovery-config.credentials"
/>
*:
</td>
<td>
<input
type=
"radio"
id=
"nocredentials"
name=
"credentials"
value=
"nocredentials"
checked
><label
for=
"nocredentials"
><fmt:message
key=
"external-service-discovery-config.credentials.nocredentials"
/></label>
</td>
</tr>
<tr>
<td>
</td>
<td>
<input
type=
"radio"
id=
"userpass"
name=
"credentials"
value=
"userpass"
><label
for=
"userpass"
><fmt:message
key=
"external-service-discovery-config.credentials.userpass"
/></label>
<label
for=
"username"
><fmt:message
key=
"external-service-discovery-config.credentials.username"
/></label>
:
<input
type=
"text"
id=
"username"
name=
"username"
size=
"25"
maxlength=
"255"
onclick=
"check('userpass')"
>
<label
for=
"password"
><fmt:message
key=
"external-service-discovery-config.credentials.password"
/></label>
:
<input
type=
"password"
id=
"password"
name=
"password"
size=
"25"
maxlength=
"1024"
onclick=
"check('userpass')"
>
</td>
</tr>
<tr>
<td>
</td>
<td>
<input
type=
"radio"
id=
"sharedsecret"
name=
"credentials"
value=
"sharedsecret"
><label
for=
"sharedsecret"
><fmt:message
key=
"external-service-discovery-config.credentials.sharedsecret"
/></label>
<input
type=
"text"
id=
"secret"
name=
"secret"
size=
"40"
maxlength=
"1024"
onclick=
"check('sharedsecret')"
>
</td>
</tr>
</table>
</admin:contentBox>
<input
type=
"submit"
name=
"addService"
value=
"
<fmt:message
key=
"external-service-discovery-config.add-service.button-caption"
/>
"
>
</form>
</body>
</html>
src/plugins/externalservicediscovery/src/web/images/delete-16x16.gif
0 → 100644
View file @
321c282d
1016 Bytes
src/plugins/externalservicediscovery/src/web/images/error-16x16.gif
0 → 100644
View file @
321c282d
1.03 KB
src/plugins/externalservicediscovery/src/web/images/info-16x16.gif
0 → 100644
View file @
321c282d
594 Bytes
src/plugins/externalservicediscovery/src/web/images/success-16x16.gif
0 → 100644
View file @
321c282d
1016 Bytes
src/plugins/externalservicediscovery/src/web/images/warning-16x16.gif
0 → 100644
View file @
321c282d
580 Bytes
src/plugins/pom.xml
View file @
321c282d
...
@@ -105,6 +105,7 @@
...
@@ -105,6 +105,7 @@
<module>
dbaccess
</module>
<module>
dbaccess
</module>
<module>
emailListener
</module>
<module>
emailListener
</module>
<module>
emailOnAway
</module>
<module>
emailOnAway
</module>
<module>
externalservicediscovery
</module>
<module>
fastpath
</module>
<module>
fastpath
</module>
<module>
gojara
</module>
<module>
gojara
</module>
<module>
hazelcast
</module>
<module>
hazelcast
</module>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment