Why does the Keycloak REST API return an "autheticatorFlow" (sic!) attribute when reading authentication/flows? - keycloak

When reading authentication flows with
kcadm.sh get authentication/flows -r master
I get this result for the builtin flows
{
"id" : "cee86f07-db10-4e84-9a5e-a9c6ae1c3703",
"alias" : "http challenge",
"description" : "An authentication flow based on challenge-response HTTP Authentication Schemes",
"providerId" : "basic-flow",
"topLevel" : true,
"builtIn" : true,
"authenticationExecutions" : [ {
"authenticator" : "no-cookie-redirect",
"authenticatorFlow" : false, <---
"autheticatorFlow" : false, <---
"requirement" : "REQUIRED",
"priority" : 10,
"userSetupAllowed" : false
}, {
"authenticatorFlow" : true,
"requirement" : "REQUIRED",
"priority" : 20,
"autheticatorFlow" : true,
"flowAlias" : "Authentication Options",
"userSetupAllowed" : false
} ]
}
That field is nowhere mentioned in the REST API documentation. Is there a deeper meaning in this, or is this just some leftover typo that is kept for compatibility (like HTTP Referer vs HTTP Referrer)? Do I have to set this undocumented field when creating a new flow via REST API?

Short story: Use "authenticatorFlow"
It would appear this is a long standing spelling typo. If you dig into the keycloak source code e.g. v15.1.1 here:
https://github.com/keycloak/keycloak/blob/15.1.1/core/src/main/java/org/keycloak/representations/idm/AbstractAuthenticationExecutionRepresentation.java#L71 You will see the misspelled "autheticatorFlow" is marked as deprecated.
#Deprecated
public void setAutheticatorFlow(boolean autheticatorFlow) {
this.authenticatorFlow = autheticatorFlow;
}
...snip...
public void setAuthenticatorFlow(boolean authenticatorFlow) {
this.authenticatorFlow = authenticatorFlow;
}
In other parts of the source you will see a setter for the correctly spelled property "authenticatorFlow" e.g. here:
https://github.com/keycloak/keycloak/blob/15.1.1/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java#L1649
(which shows the misspelling is down to the db column).
model.setAuthenticatorFlow(entity.isAutheticatorFlow());
It should be safe to use the correctly spelled "authenticatorFlow". However always evaluate for your specific version.

Related

Can't set Access-Control-Allow-Credentials header for REST API

I'm having the following issues:
I need to allow CORS only on a specific domain
I need to make sure that secure cookies are sent along with the cross-origin request.
API Gateway specifies '*' as the Access-Control-Allow-Origin header and I need to only allow "example.com".
I found that I can do this by adding the following in override.ts in the rest API resource folder:
import { AmplifyApiRestResourceStackTemplate } from '#aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiRestResourceStackTemplate) {
// Change the default CORS response header Access-Control-Allow-Origin from "'*'" to the API's domain
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Origin'] = {
'Fn::Sub': "'https://www.example.com'"
};
}
This seems unreasonably hacky, but whatever.
But I can't seem to solve for the Access-Control-Allow-Credentials header... This doesn't work:
import { AmplifyApiRestResourceStackTemplate } from '#aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiRestResourceStackTemplate) {
// Change the default CORS response header Access-Control-Allow-Origin from "'*'" to the API's domain
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Origin'] = {
'Fn::Sub': "'https://www.example.com'"
};
// ADDING THIS ...
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Credentials'] = "true";
}
I get multiple errors, but it's basically complaining with this error for each of my REST endpoints:
Unable to put integration response on 'OPTIONS' for resource at path '/oauth/hubspot': Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression specified: true]
I get similar errors if I try any of the following:
// with quotes inside quotes
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Credentials'] = "'true'";
// this structure
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Credentials'] = {
'Fn::Sub': "'true'"
};
The thing is, I could easily do all this myself if Amplify would just let me override how I handle the OPTIONS request, and send it to my lambda function....
VICTORY!
I'd still be interested in any suggested approaches, but this worked for me:
// This file is used to override the REST API resources configuration
import { AmplifyApiRestResourceStackTemplate } from '#aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiRestResourceStackTemplate) {
delete resources.restApi.body.paths['/v1'].options;
delete resources.restApi.body.paths['/v1/{proxy+}'].options;
}
Basically, it's me telling Amplify to get out of the way and let me handle the OPTIONS request myself. So this leaves the "ANY" method on the endpoint so that the OPTIONS request flows through to the LAMBDA that's already configured. I already had the code in there to handle OPTIONS requests, so... It. Just. Worked.
I know it's been six months since you asked this question, but it's something i've just been smashing my head against now.
I had exactly the same issue:
I need CORS across several domains, but I can't use Access-Control-Allow-Origin: '*' because in the browser I am calling the api with { withCredentials: true }.
My Api's back into a lambda function which correctly handles the CORS preflight on the OPTION request. (ie. it returns Access-Control-Allow-Origin: https://permitted.origin.goes.here and associated headers).
But I get CORS errors because the AWS API Gateway response for OPTION is using a predefined MOCK response, which does not allow any other value for Access-Control-Allow-Origin than '*'.
(this was all generated by Amplify).
Anyways, I tried your method of deleting the OPTION handler, but that still did not work for me.
Eventually, after configuring it correctly in the AWS API Gateway interface, exporting the swagger and replicating that in the override.ts file, I finally got it cleanly working.
this was my code in override.ts:
import { AmplifyApiRestResourceStackTemplate } from '#aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiRestResourceStackTemplate) {
const { paths } = resources.restApi.body;
Object.keys(paths).forEach((path) => {
if (!!paths[path].options) {
const uri = paths[path]['x-amazon-apigateway-any-method']['x-amazon-apigateway-integration'].uri;
paths[path].options = {
"responses" : {
"200" : {
"description" : "200 response",
"headers" : {
"Access-Control-Allow-Credentials" : {
"type" : "string"
},
"Access-Control-Allow-Origin" : {
"type" : "string"
},
"Access-Control-Allow-Methods" : {
"type" : "string"
},
"Access-Control-Allow-Headers" : {
"type" : "string"
}
}
}
},
"x-amazon-apigateway-integration" : {
"httpMethod" : "POST",
"uri" : uri,
"responses" : {
"default" : {
"statusCode" : "200"
}
},
"passthroughBehavior" : "when_no_match",
"contentHandling" : "CONVERT_TO_TEXT",
"type" : "aws_proxy"
}
}
}
});
}
Now I can return secure cookies to a browser app from the AWS REST API without choking on CORS errors.
good luck!

Cannot read property 'getUniqueId' of undefined

sorry to bother anyone,but i really need help for this,i want to retrieve chat from database(which i already ask this question before),but i try to googling and read all the documentation,and i assumed that i have found the solution,i read the converse.js documentation about developer api,in the Archiving group section,and i got this :
require(['converse'], function (converse) {
converse.plugins.add('myplugin', {
initialize: function () {
this._converse.api.archive.query({'with': 'admin2#localhost'});
}
});
converse.initialize({
jid: 'admin3#localhost',
authentication: 'prebind',
prebind_url: 'bind/bind.php',
allow_logout: false,
debug : true,
whitelisted_plugins: ['converse-inverse','converese-mam','converse-singleton','converse-muc-embedded','myplugin'],
archived_messages_page_size : 20,
message_archiving : "always",
auto_list_rooms: false,
show_chatstate_notifications:true,
message_carbons : true,
sounds_path : "sounds/",
auto_reconnect : true,
use_vcard : true,
auto_subscribe: false,
keepalive : true,
show_send_button:true,
archived_messages_page_size : 20,
bosh_service_url: 'http://localhost:5280/http-bind',
hide_muc_server: false,
play_sounds : true,
show_controlbox_by_default: false,
xhr_user_search: false
});
});
i try it,but i got this error :
Cannot read property 'getUniqueId' of undefined
at Object._converse.queryForArchivedMessages (converse-mam.js:266)
at Object.initialize (dev.html:30)
at PluginSocket.initializePlugin (pluggable.js:196)
at arrayEach (lodash.js:537)
at Object.forEach (lodash.js:9359)
at PluginSocket.initializePlugins (pluggable.js:227)
at Object.initPlugins (converse-core.js:1854)
at Object._converse.initialize (converse-core.js:1875)
at Object.initialize (converse-core.js:2037)
at dev.html:36
i am sorry if this question's kinda simple or stupid,but i really new in using converse.js,and i really like to use and learn more about converse.js in the future because it full features and documentation.
The initialize method of a Converse.js plugin gets called when Converse.js itself gets initialized.
This happens before the user has been logged in (regardless whether that happens automatically or manually).
So you're calling this._converse.api.archive.query({'with': 'admin2#localhost'}); before the user has been logged and an XMPP connection and session has been established.
Instead, you should first listen for the connection event, and then do your query.
converse.plugins.add('myplugin', {
initialize: function () {
var _converse = this._converse;
_converse.on('connected', function () {
_converse.api.archive.query({'with': 'admin2#localhost'});
});
}
});

Atmosphere request.onOpen never gets called. Client-Server connection stopped showing: "101 switching protocols"

I have downloaded the "atmosphere-chat" (jersey) and modified a little because I wanted it to be running inside Jetty.
Everithing is working on this side (in stand alone way). Atmosphere 2.2.0-RC3 / Jetty jetty-9.2.0.M1
But when I put those inside Mule the request.onOpen is never called.
Here is the piece of javascript code (I didn't change from the example):
var request = { url: 'http://myIP:8080/sc.eco/servlet/chat/',
contentType : "application/json",
logLevel : 'debug',
transport : 'websocket' ,
trackMessageLength : true,
fallbackTransport: 'long-polling'};
request.onOpen = function(response) {
content.html($('<p>', { text: 'Atmosphere connected using ' + response.transport }));
input.removeAttr('disabled').focus();
status.text('Choose name:');
};
It's shown on the console "Websocket successfully opened":
but it's stacked in this request:
Request URL:ws://myIP:8080/sc.eco/servlet/chat/?X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.2.1-jquery&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&X-Cache-Date=0&Content-Type=application/json&X-atmo-protocol=true
Request Method:GET
Status Code:101 Switching Protocols
¿Any idea? :S
I had the same problem. I could resolve this by setting enableProtocol to false in the request config.
In your case this would look like this:
var request = { url: 'http://myIP:8080/sc.eco/servlet/chat/',
contentType : "application/json",
logLevel : 'debug',
transport : 'websocket' ,
trackMessageLength : true,
fallbackTransport: 'long-polling',
enableProtocol: false };
I came to this solution was originally proposed in this thread.

How can I wrap each API response into a standard reply object in SailsJS?

I'm new to Sails and I'm trying to figure out the best/proper method for returning a standard object for every API response.
The container our front-end requires is:
{
"success": true/false,
"session": true/false,
"errors": [],
"payload": []
}
Currently, I’m overwriting the blueprint actions in each controller like this example (which just seems so very, very wrong):
find : function( req, res ){
var id = req.param( 'id' );
Foo.findOne( { id : id } ).exec( function( err, aFoo ){
res.json(
AppSvc.jsonReply(
req,
[],
aFoo
), 200
);
});
}
And in AppSvc.js:
jsonReply : function( req, errors, data ){
return {
success : ( errors && errors.length ? false : true ),
session : ( req.session.authenticated === true ),
errors : ( errors && errors.length ? errors : [] ),
payload : ( data ? data : [] )
};
}
Additionally, I’ve had to modify each res.json() method for each default response (badRequest, notFound,etc). Again, this feels so wrong.
So, how do I properly funnel all API responses into a standard container?
Sails custom responses are great for this.
If you look at the blueprint code, you'll see that each one calls res.ok when it's done: https://github.com/balderdashy/sails/blob/master/lib/hooks/blueprints/actions/find.js#L63
You can add your own file - ok.js - to api/responses/ - which will override the default built in handler.
https://github.com/balderdashy/sails/blob/master/lib/hooks/responses/defaults/ok.js <- just copy and paste this to start, and adapt as you need.

Retrieving data from MongoDB with ExtJS using the REST API

For the need of a simple demonstrator, I've created a simple grid panel in ExtJS, and now i'm trying to fill it with data coming from MongoDB. I heard about Node.JS and stuff but there I just want to use the REST API of MongoDB to retrieve the data.
Note : I'm new in ExtJS and REST request.
My problem is that when loading my page, there is no panel created and firebug tells me :
""NetworkError: 400 Bad Request - http://xxx.xxx.xx.xx:28017/mydb/device/find?_dc=1374225874880&page=1&start=0&limit=25""
If I copy and paste the URL http://xxx.xxx.xx.xx:28017/mydb/device/find?_dc=1374225874880&page=1&start=0&limit=25 I can see the data, so that means that the Mongo data are accessible through URL.
Note that I dont' know where the "page=1&start=0&limit=25" param of the URL comes from, it wasn't implemented by me.
My code that is supposed to load the data is in my Store component of my MVC :
Ext.define('AM.store.Users', {
extend: 'Ext.data.Store',
model: 'AM.model.User',
autoLoad: true,
proxy: {
type: 'rest',
url: 'http://xxx.xxx.xx.xx:28017/mydb/device/find',
reader: {
type: 'json',
root: 'rows',
idProperty: '_id'
}
}
});
And this is what shows the Mongo URL :
{
"offset" : 0,
"rows": [
{ "_id" : "SheevaPlug", "manufacturer" : "GlobalScale" }
],
"total_rows" : 1 ,
"query" : {} ,
"millis" : 0
}
The mapping in the Model seems correct too :
Ext.define('AM.model.User', {
extend: 'Ext.data.Model',
fields: ['_id', 'manufacturer']
});
Thanks by advance if you can help me !
Cheers,
Vincent
Use Node.js to create MongoDB web services that you will call with Sencha.