I'm building a kext for an extra layer of security on OS X (built around KAtuh). I'm using a client in userspace that connects to the kext over sockets (as advised by Apple), and basically controls the kext. Because the product is supposed to provide extra security for OS X, it is important that it is "as secure as possible" against attacks. One attack vector is the following: A malicious process impersonates the client and sends malicious control data to the kext, disabling the security mechanism.. I want to prevent this by doing authentication upon connection. Here are my solutions:
Run the client as root, use CTL_FLAG_PRIVILEGED flag to ensure only root clients can connect to the kext. I'm not sure if I want to have my client run in privileged mode (again: extra attack vector).
Let the kext be connected to only one client. However, this is easily by-passable.
Ideally, I want to verify the identity of the client that connects through static int ctl_connect(kern_ctl_ref ctl_ref, struct sockaddr_ctl *sac, void **unitinfo). How can I do this?
I can also do packet authentication in static int ctl_set(kern_ctl_ref ctl_ref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len), however, I would have to come up with a dynamic shared secret. I was thinking about secret = SHA256(getUDID()), but AFAIK there are no crypto KPI's available, neither a way to getUDID() from kernelspace.
Are there any other idea's on doing "proper" authentication of clients?
I have asked Apple's Developer Tech Support this question, and they have said the only supported way to restrict user client access to kexts is to distinguish between root and non-root processes.
Personally, for the purposes of reducing the attack surface, it would indeed be useful to drop user client privileges. The Linux way of checking for a specific group membership seems like it should work on OS X too. (For example, you typically need to be part of the 'kvm' group to use the KVM virtualisation technology on Linux.) The only way to become a member of the group is via root privileges (setting up the Launch Daemon's GroupName requires root privileges) so this should be secure. I have yet to try this myself, but I've got 2 projects where this would make sense so I'll give it a go and will update this answer with my findings.
Apple has implemented functionality in the AMFI kext (<sys/codesign.h> header) that can be used to obtain the TeamID from a signed binary. If this header would be public, this is exactly what could be used to authenticate the client process connecting to the kext.
/*
* Function: csfg_get_teamid
*
* Description: This returns a pointer to
* the teamid for the fileglob fg
*/
const char *
csfg_get_teamid(struct fileglob *fg)
{
struct ubc_info *uip;
const char *str = NULL;
vnode_t vp;
if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
return NULL;
vp = (struct vnode *)fg->fg_data;
if (vp == NULL)
return NULL;
vnode_lock(vp);
if (!UBCINFOEXISTS(vp))
goto out;
uip = vp->v_ubcinfo;
if (uip == NULL)
goto out;
if (uip->cs_blobs == NULL)
goto out;
/* It is OK to extract the teamid from the first blob
because all blobs of a vnode must have the same teamid */
str = uip->cs_blobs->csb_teamid;
out:
vnode_unlock(vp);
return str;
}
Related
I want to protect my users data as much as possible! In this scenario I'm trying to protect data-in-use/data-in-memory against certain memory attacks or at least make it more difficult for nefarious people to get at my users' data.
I do not really understand how Flutter & Dart handle memory or really any language for that matter. So I'm looking for some insight, direction or confirmation in what I'm trying to do here without needing a masters in computer science. While I'm using Flutter/Dart this is also a generalized question.
My modus operandi here is simple, when done with some sensitive data I want to:
Encrypt data for memory zero
Zero all encrypted memory
Does this do what I intend?
If this does not do what I intend or is pointless in any way, please explain why.
/*
- Symmetric encryption
- Encryption before putting data into transit
- This symmetric key and nonce are asymmetrically encrypted with authorized users public keys
- Authorized users can decrypt the key
- Sensitive data is encrypted then zeroed
*/
Future<String> symmetricallyEncrypt(Sale sale) async {
String saleJson = jsonEncode(sale);
final symmetricKey = await secureStorage.read(key: kSSKeySymmetric);
final symmetricNonce = await secureStorage.read(key: kSSKeySymmetricNonce);
final symmetricCypher = AesCrypt(padding: PaddingAES.pkcs7, key: symmetricKey!);
final encryptedSale = symmetricCypher.gcm.encrypt(inp: saleJson, iv: symmetricNonce!);
/* --- ENCRYPTED ZERO --- */
encryptedZero(saleJson);
encryptedZero(symmetricKey);
encryptedZero(symmetricNonce);
encryptedZero(symmetricCypher.toString());
return encryptedSale;
}
/*
Encryption zero method
- Encrypts shredding input
- Zeros all inputs
*/
Future<void> encryptedZero(String shredding) async {
String? asymmetricPublicZeroKey = await secureStorage.read(key: kSSKeyMemoryZeroAsymmetricPublic);
String encryptedShredding = RSAPublicKey.fromPEM(asymmetricPublicZeroKey!).encrypt(shredding);
asymmetricPublicZeroKey = '';
encryptedShredding = '';
shredding = '';
}
I get what you're asking but think it's not the right way to think about the security of your memory.
What's the threat actor - another process? The operating system? The root user?
If you don't trust the root user, the OS, and the hardware, you've already lost.
If you have to trust them, then what else is your threat actor? You have to trust your application. So the only other things are other applications running on the same system.
The operating system prevents other applications from reading your memory space (SEG FAULT, etc). And the OS zeros out your application's memory pages before passing them to another process.
But that's not the whole story - read https://security.stackexchange.com/questions/29019/are-passwords-stored-in-memory-safe for even more details.
I am developing secure payment APIs, and I want to avoid replay attacks with manipulation of the parameters in the url. For example in the following API call:
https://api.payment.com/wallet/transfer?from_account=123&to_account=456&amount=100
Once this API call is executed, someone with enough knowledge can execute the same API call by modifying any of the three parameters to his/her own advantage. I have thought of issuing a temporary token (transaction token) for each transaction. But this also doesn't sounds like enough.
Can anyone suggest the best way to mitigate replay attacks with parameters tampering?
THE API SERVER
I am developing secure payment APIs, and I want to avoid replay attacks with manipulation of the parameters in the url.
Before we dive into addressing your concerns it's important to first clarify a common misconception among developers, that relates to knowing the difference between who vs what is accessing the API server.
The difference between who and what is accessing the API server.
This is discussed in more detail in this article I wrote, where we can read:
The what is the thing making the request to the API server. Is it really a genuine instance of your mobile app, or is it a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?
The who is the user of the mobile app that we can authenticate, authorize and identify in several ways, like using OpenID Connect or OAUTH2 flows.
If the quoted text is not enough for you to understand the differences, then please go ahead and read the entire section of the article, because without this being well understood you are prone to apply less effective security measures in your API server and clients.
SECURITY LAYERS AND PARAMETERS IN THE URL
For example in the following API call:
https://api.payment.com/wallet/transfer?from_account=123&to_account=456&amount=100
Security is all about applying as many layers of defence as possible in order to make the attack as harder and laborious as possible, think of it as the many layers in an onion you need to peel to arrive to the center one.
Attackers will always look for the most easy targets, the lower hanging fruit in the tree, because they don't want to resort to use a ladder when they can take the fruit from another tree with lower hanging fruit ;)
So one of the first layers of defense is to avoid using parameters in the url for sensitive calls, thus I would use a POST request with all the parameters in the body of the request, because this type of request cannot be done by simply copy paste the url into the browser or any other tool, thus they require more effort and knowledge to be performed, aka the fruit is more high in the tree for the attacker.
Another reason is that GET requests end up in the logs of the servers, thus can be accidentally exposed and easily replayed.
REPLAY ATTACKS FOR API CALLS
Once this API call is executed, someone with enough knowledge can execute the same API call by modifying any of the three parameters to his/her own advantage.
Yes they can, and they can learn how your API works even if you don't have public documentation for it, they just need to reveres engineer it with the help of any open source tool for mobile apps and web apps.
I have thought of issuing a temporary token (transaction token) for each transaction. But this also doesn't sounds like enough.
Yes it's not enough because this temporary token can be stolen via a MitM attack, just like a show in the article Steal That Api Key With a Man in the Middle Attack:
So, in this article you will learn how to setup and run a MitM attack to intercept https traffic in a mobile device under your control, so that you can steal the API key. Finally, you will see at a high level how MitM attacks can be mitigated.
So after performing the MitM attack to steal the token it's easy to use curl, Postman or any other similar tool to make the requests to the API server just like if you are the genuine who and what the API server expects.
MITIGATE REPLAY ATTACKS
Improving on Existing Security Defence
I have thought of issuing a temporary token (transaction token) for each transaction. But this also doesn't sounds like enough.
This approach is good but not enough as you alreay noticed, but you can improve it, if not have done it already, by making this temporary token usable only one time.
Another important defence measure is to not allow the requests with same amount and same recipients(from_account, to_account) be repeated in sequence, even if they have a new temporary token.
Also don't allow requests from the same source to be made to fast, specially if they are intended to come from human interactions.
This measures on their own will not totally solve the issue, but add some more layers into the onion.
Using HMAC for the One Time Token
In order to try to help the server to be confident about who and what is making the request you can use a Keyed-Hash Message Authentication Code (HMAC) which is designed to prevent hijacking and tampering, and as per Wikipedia:
In cryptography, an HMAC (sometimes expanded as either keyed-hash message authentication code or hash-based message authentication code) is a specific type of message authentication code (MAC) involving a cryptographic hash function and a secret cryptographic key. As with any MAC, it may be used to simultaneously verify both the data integrity and the authenticity of a message.
So you could have the client creating an HMAC token with the request url, user authentication token, your temporary token, and the time stamp that should be also present in a request header. The server would then grab the same data from the request and perform it's own calculation of the HMAC token, and only proceed with the request if it's own result matches the one for the HMAC token header in the request.
For a practical example of this in action you can read part 1 and part 2 of this blog series about API protection techniques in the context of a mobile app, that also features a web app impersonating the mobile app.
So you can see here how the mobile app calculates the HMAC, and here how the Api server calculates and validates it. But you can also see here how the web app fakes the HMAC token to make the API server think that the requests is indeed from who and what it expects to come from, the mobile app.
Mobile App Code::
/**
* Compute an API request HMAC using the given request URL and authorization request header value.
*
* #param context the application context
* #param url the request URL
* #param authHeaderValue the value of the authorization request header
* #return the request HMAC
*/
private fun calculateAPIRequestHMAC(url: URL, authHeaderValue: String): String {
val secret = HMAC_SECRET
var keySpec: SecretKeySpec
// Configure the request HMAC based on the demo stage
when (currentDemoStage) {
DemoStage.API_KEY_PROTECTION, DemoStage.APPROOV_APP_AUTH_PROTECTION -> {
throw IllegalStateException("calculateAPIRequestHMAC() not used in this demo stage")
}
DemoStage.HMAC_STATIC_SECRET_PROTECTION -> {
// Just use the static secret to initialise the key spec for this demo stage
keySpec = SecretKeySpec(Base64.decode(secret, Base64.DEFAULT), "HmacSHA256")
Log.i(TAG, "CALCULATE STATIC HMAC")
}
DemoStage.HMAC_DYNAMIC_SECRET_PROTECTION -> {
Log.i(TAG, "CALCULATE DYNAMIC HMAC")
// Obfuscate the static secret to produce a dynamic secret to initialise the key
// spec for this demo stage
val obfuscatedSecretData = Base64.decode(secret, Base64.DEFAULT)
val shipFastAPIKeyData = loadShipFastAPIKey().toByteArray(Charsets.UTF_8)
for (i in 0 until minOf(obfuscatedSecretData.size, shipFastAPIKeyData.size)) {
obfuscatedSecretData[i] = (obfuscatedSecretData[i].toInt() xor shipFastAPIKeyData[i].toInt()).toByte()
}
val obfuscatedSecret = Base64.encode(obfuscatedSecretData, Base64.DEFAULT)
keySpec = SecretKeySpec(Base64.decode(obfuscatedSecret, Base64.DEFAULT), "HmacSHA256")
}
}
Log.i(TAG, "protocol: ${url.protocol}")
Log.i(TAG, "host: ${url.host}")
Log.i(TAG, "path: ${url.path}")
Log.i(TAG, "Authentication: $authHeaderValue")
// Compute the request HMAC using the HMAC SHA-256 algorithm
val hmac = Mac.getInstance("HmacSHA256")
hmac.init(keySpec)
hmac.update(url.protocol.toByteArray(Charsets.UTF_8))
hmac.update(url.host.toByteArray(Charsets.UTF_8))
hmac.update(url.path.toByteArray(Charsets.UTF_8))
hmac.update(authHeaderValue.toByteArray(Charsets.UTF_8))
return hmac.doFinal().toHex()
}
API server code:
if (DEMO.CURRENT_STAGE == DEMO.STAGES.HMAC_STATIC_SECRET_PROTECTION) {
// Just use the static secret during HMAC verification for this demo stage
hmac = crypto.createHmac('sha256', base64_decoded_hmac_secret)
log.info('---> VALIDATING STATIC HMAC <---')
} else if (DEMO.CURRENT_STAGE == DEMO.STAGES.HMAC_DYNAMIC_SECRET_PROTECTION) {
log.info('---> VALIDATING DYNAMIC HMAC <---')
// Obfuscate the static secret to produce a dynamic secret to use during HMAC
// verification for this demo stage
let obfuscatedSecretData = base64_decoded_hmac_secret
let shipFastAPIKeyData = new Buffer(config.SHIPFAST_API_KEY)
for (let i = 0; i < Math.min(obfuscatedSecretData.length, shipFastAPIKeyData.length); i++) {
obfuscatedSecretData[i] ^= shipFastAPIKeyData[i]
}
let obfuscatedSecret = new Buffer(obfuscatedSecretData).toString('base64')
hmac = crypto.createHmac('sha256', Buffer.from(obfuscatedSecret, 'base64'))
}
let requestProtocol
if (config.SHIPFAST_SERVER_BEHIND_PROXY) {
requestProtocol = req.get(config.SHIPFAST_REQUEST_PROXY_PROTOCOL_HEADER)
} else {
requestProtocol = req.protocol
}
log.info("protocol: " + requestProtocol)
log.info("host: " + req.hostname)
log.info("originalUrl: " + req.originalUrl)
log.info("Authorization: " + req.get('Authorization'))
// Compute the request HMAC using the HMAC SHA-256 algorithm
hmac.update(requestProtocol)
hmac.update(req.hostname)
hmac.update(req.originalUrl)
hmac.update(req.get('Authorization'))
let ourShipFastHMAC = hmac.digest('hex')
// Check to see if our HMAC matches the one sent in the request header
// and send an error response if it doesn't
if (ourShipFastHMAC != requestShipFastHMAC) {
log.error("\tShipFast HMAC invalid: received " + requestShipFastHMAC
+ " but should be " + ourShipFastHMAC)
res.status(403).send()
return
}
log.success("\nValid HMAC.")
Web APP code:
function computeHMAC(url, idToken) {
if (currentDemoStage == DEMO_STAGE.HMAC_STATIC_SECRET_PROTECTION
|| currentDemoStage == DEMO_STAGE.HMAC_DYNAMIC_SECRET_PROTECTION) {
var hmacSecret
if (currentDemoStage == DEMO_STAGE.HMAC_STATIC_SECRET_PROTECTION) {
// Just use the static secret in the HMAC for this demo stage
hmacSecret = HMAC_SECRET
}
else if (currentDemoStage == DEMO_STAGE.HMAC_DYNAMIC_SECRET_PROTECTION) {
// Obfuscate the static secret to produce a dynamic secret to
// use in the HMAC for this demo stage
var staticSecret = HMAC_SECRET
var dynamicSecret = CryptoJS.enc.Base64.parse(staticSecret)
var shipFastAPIKey = CryptoJS.enc.Utf8.parse($("#shipfast-api-key-input").val())
for (var i = 0; i < Math.min(dynamicSecret.words.length, shipFastAPIKey.words.length); i++) {
dynamicSecret.words[i] ^= shipFastAPIKey.words[i]
}
dynamicSecret = CryptoJS.enc.Base64.stringify(dynamicSecret)
hmacSecret = dynamicSecret
}
if (hmacSecret) {
var parser = document.createElement('a')
parser.href = url
var msg = parser.protocol.substring(0, parser.protocol.length - 1)
+ parser.hostname + parser.pathname + idToken
var hmac = CryptoJS.HmacSHA256(msg, CryptoJS.enc.Base64.parse(hmacSecret)).toString(CryptoJS.enc.Hex)
return hmac
}
}
return null
}
NOTE: While the above code is not using the exact same parameters that you would use in your case, it is a good starting pointing for you to understand the basics of it.
As you can see the way the HMAC token is calculated across mobile app, Api server and the Web app are identical in the semantics of the logic, thus resulting in the same HMAC token, and this way the Web app is able to defeat the Api server defense to only accept valid request from the mobile app.
The bottom line here is that anything you place in the client code can be reverse engineered in order to replicate it in another client. So should I use HMAC tokens in my use case?
Yes, because it's one more layer in the onion or a fruit more high in the tree.
Can I do better?
Yes you can do, just keep reading...
Enhance and Strength the Security
Can anyone suggest the best way to mitigate replay attacks with parameters tampering?
Going with the layered defence approach once more, you should look to other layered approaches that will allow your API server to be more confident about who and waht is accessing it.
So if the clients of you API server are only mobile apps, then please read this answer for the question How to secure an API REST for mobile app?.
In the case you need to secure an API that serves both a mobile and web app, then see this another answer for the question Unauthorized API Calls - Secure and allow only registered Frontend app.
GOING THE EXTRA MILE
Now I would like to recommend you the excellent work of the OWASP foundation:
The Web Security Testing Guide:
The OWASP Web Security Testing Guide includes a "best practice" penetration testing framework which users can implement in their own organizations and a "low level" penetration testing guide that describes techniques for testing most common web application and web service security issues.
The Mobile Security Testing Guide:
The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.
After login when redirecting the user using context.AuthenticateResult = new AuthenticateResult(<destination>, subject, name, claims) the partial cookie gets so big that it contains up to 4 chunks and ends up causing "request too big" error.
The number of claims is not outrageous (in the 100 range) and I haven't been able to consistently reproduce this on other environments, even with larger number of claims. What else might be affecting the size of this cookie payload?
Running IdSrv3 2.6.1
I assume that you are using some .NET Framework clients, because all of these problems are usually connected with the Microsoft.Owin middleware, that has some encryption that causes the cookie to get this big.
The solution for you is again part of this middleware. All of your clients (using the Identity Server as authority) need to have a custom IAuthenticationSessionStore imlpementation.
This is an interface, part of Microsoft.Owin.Security.Cookies.
You need to implement it according to whatever store you want to use for it, but basically it has the following structure:
public interface IAuthenticationSessionStore
{
Task RemoveAsync(string key);
Task RenewAsync(string key, AuthenticationTicket ticket);
Task<AuthenticationTicket> RetrieveAsync(string key);
Task<string> StoreAsync(AuthenticationTicket ticket);
}
We ended up implementing a SQL Server store, for the cookies. Here is some example for Redis Implementation, and here is some other with EF DbContext, but don't feel forced to use any of those.
Lets say that you implement MyAuthenticationSessionStore : IAuthenticationSessionStore with all the values that it needs.
Then in your Owin Startup.cs when calling:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
SessionStore = new MyAuthenticationSessionStore()
CookieName = cookieName
});
By this, as the documentation for the IAuthenticationSessionStore SessionStore property says:
// An optional container in which to store the identity across requests. When used,
// only a session identifier is sent to the client. This can be used to mitigate
// potential problems with very large identities.
In your header you will have only the session identifier, and the identity itself, will be read from the Store that you have implemented
I need to communicate between multiple clients. When I try to run file (multiple terminals) I get same identity. So I let router socket to automatically set the UUID. But what I found I cannot use that identity to store at server for routing between multiple clients.
How would I handle multiple clients IDs?
I am trying to build an asynchronous Chat server. I am following an approach of each client with dealer socket connects to server ( ROUTER-type sockets ). Server then extract the clients IDs ( set manually ) and reads the message and route accordingly.
#include "zhelpers.hpp"
#include <iostream>
#include <string>
int main(void) {
zmq::context_t context(1);
zmq::socket_t backend (context, ZMQ_DEALER);
backend.setsockopt( ZMQ_IDENTITY, "mal2", 4);
backend.connect("tcp://localhost:5559");
std::string input;
std::cout <<"you are joinning" << std::endl;
while(1){
getline (std::cin, input);
s_send (backend, input);
zmq::pollitem_t items [] = {
{ backend, 0, ZMQ_POLLIN, 0 }
};
zmq::poll (items, 1, -1);
if (items [0].revents & ZMQ_POLLIN) {
std::string identity = s_recv (backend);
std::string request = s_recv (backend);//receive reply back from router which might be other client
std::cout<<"identity="<<identity<<"reques="<<request<<std::endl;
} //ending if
}//ending while
return 0;
}
Memento
It has been proved by decades to rather design a system based on all collected requirements, i.e. before coding, not vice versa.
This way your analysis will list all the requirements before deciding on messaging and signalling layer, avoiding situations "And also I want to add this and that ..."
UUID
If you decide to create a disposable or persistent UUID-s on each client side, you face a challenge to ensure both temporal uniqueness & randomisation.
If you decide to assign UUID-s from a ChatSERVER side, you need an additional signalling layer, besides the chat-transport.
Answer to "How would I handle multiple clients ID" is not answer-able without the other requirements you are sure to have ( or will sooner or later realise to face 'em, on-the-fly )
Time is money
As said above, good projects start with proper and thorough requirements engineering & validation. The product coding than spans a minimum amount of time, compared to a "Aha-based & trouble-shooting responsive engineering".
i am working on XMPP chat app in android, using Prosody as XMPP server.
i have written code for create Multi User Chat room and its working fine when i am using Openfire as server, but when i use Prosody as server it gives me error, as
Creation failed - Missing acknowledge of room creation.:
i.e group is already exist. but it throws same error for any name(New Group Name).
if i replace muc.create(name); with muc.join(name); it creates group. but then i am unable to configure group/room properties.
below is my Prosody Config File:-
modules_enabled = {
-- Generally required
"roster"; -- Allow users to have a roster. Recommended ;)
"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
--"tls"; -- Add support for secure TLS on c2s/s2s connections
"dialback"; -- s2s dialback support
"disco"; -- Service discovery
-- Not essential, but recommended
"private"; -- Private XML storage (for room bookmarks, etc.)
"vcard"; -- Allow users to set vCards
-- These are commented by default as they have a performance impact
--"privacy"; -- Support privacy lists
--"compression"; -- Stream compression
-- Nice to have
"version"; -- Replies to server version requests
"uptime"; -- Report how long server has been running
"time"; -- Let others know the time here on this server
"ping"; -- Replies to XMPP pings with pongs
"pep"; -- Enables users to publish their mood, activity, playing music and more
"register"; -- Allow users to register on this server using a client and change passwords
-- Admin interfaces
"admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
--"admin_telnet"; -- Opens telnet console interface on localhost port 5582
-- HTTP modules
"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
"http_files"; -- Serve static files from a directory over HTTP
-- Other specific functionality
"groups"; -- Shared roster support
--"announce"; -- Send announcement to all online users
--"welcome"; -- Welcome users who register accounts
--"watchregistrations"; -- Alert admins of registrations
--"motd"; -- Send a message to users when they log in
--"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
};
allow_registration = true -- Allow users to register new accounts
VirtualHost "localhost"
---Set up a MUC (multi-user chat) room server on conference.example.com:
Component "conference.localhost" "muc"
My Group Create Code is:-
MultiUserChat muc = new MultiUserChat(xmppConnection, room);
// Create the room
SmackConfiguration.setPacketReplyTimeout(2000);
String name = xmppConnection.getUser();
System.out.println("name:- " + name);
String name1 = name.substring(0, name.lastIndexOf("#"));
System.out.println("name1:- " + name1);
System.out.println("group name:- " + grpName);
muc.create(name1);
// Get the the room's configuration form
Form form = muc.getConfigurationForm();
// Create a new form to submit based on the original form
Form submitForm = form.createAnswerForm();
// Add default answers to the form to submit
for (Iterator<FormField> fields = form.getFields(); fields.hasNext();) {
FormField field = (FormField) fields.next();
if (!FormField.TYPE_HIDDEN.equals(field.getType()) && field.getVariable() != null) {
// Sets the default value as the answer
submitForm.setDefaultAnswer(field.getVariable());
}
}
// muc.sendConfigurationForm(submitForm);
Form f = new Form(Form.TYPE_SUBMIT);
try {
muc.sendConfigurationForm(f);
} catch (XMPPException xe) {
System.out.println( "Error on sendConfigurationForm:- " + xe);
}
// Sets the new owner of the room
List<String> owners = new ArrayList<String>();
owners.add(xmppConnection.getUser());
submitForm.setAnswer("muc#roomconfig_roomowners", owners);
submitForm.setAnswer("muc#roomconfig_persistentroom", true);
muc.sendConfigurationForm(submitForm);
where i am going wrong?
This is caused by non-standard behavior of prosody's MUC plugin. Basically it behaves like a MUC room already exists, even if it's not the case.
You have to possibilites:
Using Smack's (since 4.0) MultiUserChat.createOrJoin(String), will succeed in this case. See also SMACK-557
Setting prosody's mod MUC property restrict_room_creation to true, will make prosody behaves as specified in XEP-45
Since you want to configure the room, the only option is changing prosody's restrict_room_creation setting.
Note that there is another issue in Smack's MUC code, that will be fixed in Smack 4.1 and likely there will also be a workaround implemented in prosody. But I don't think that this issue is related here, the info is just for completeness.