I'm attempting to use the Coldfusion Login Wizard to query Active Directory, however I'm having a problem with the directory structure. Essentially, I need to query from multiple nested OUs that are under the same root OU. So for instance, the OU "Admin" and "Staff" are children of the OU "School Users". I'm able to use the following code to successfully query each sub OU individully, but I can't query the root (School Users) OU.
<!-- This is the include file that sets the attributes and collects the username and password passed by the user-->
<cfset args.authtype = "LDAP">
<cfset args.server = "ads.schoolname.org">
<cfset args.port = "389">
<cfset args.start = "dc=schoolname, dc=org">
<cfset args.suser = "usr">
<cfset args.spwd = "password">
<cfset args.queryString = "cn={username},OU=ADMIN,OU=SCHOOL USERS,DC=SCHOOLNAME,DC=ORG">
<!-- The following is a snippet of the authenticate file that takes the above info and attempts to query and authenticate the user -->
<cffunction name="ldapauth" access="private" output="true" returntype="struct" hint="Authenticate against a LDAP server." >
<cfargument name="lServer" required="true" hint="The LDAP server.">
<cfargument name="lPort" hint="The port the LDAP server is running on.">
<cfargument name="sUsername" required="true" hint="The username that was set in the Login Wizard.">
<cfargument name="sPassword" required="true" hint="The password that was set in the Login Wizard.">
<cfargument name="uUsername" required="true" hint="The username that was passed in from the client.">
<cfargument name="uPassword" required="true" hint="The password that was passwd in from the client.">
<cfargument name="sQueryString" required="true" hint="The string to be passed to the LDAP server">
<cfargument name="lStart" required="true">
<cfset var retargs = StructNew()>
<cfset var username = replace(sQueryString,"{username}",uUserName)>
<cfldap action="QUERY"
name="userSearch"
attributes="dn"
start="#arguments.lStart#"
server="#arguments.lServer#"
port="#arguments.lPort#"
username="#arguments.sUsername#"
password="#arguments.sPassword#" >
<!--- If user search failed or returns 0 rows abort --->
<cfif userSearch.recordCount EQ "" >
<cfoutput>Error</cfoutput>
</cfif>
<!--- pass the user's DN and password to see if the user authenticates
and get the user's roles --->
<cfldap
action="QUERY"
name="auth"
attributes="dn,roles"
start="#arguments.lStart#"
server="#arguments.lServer#"
port="#arguments.lPort#"
username="#username#"
password="#arguments.uPassword#" >
<!--- If the LDAP query returned a record, the user is valid. --->
<cfif auth.recordCount>
<cfset retargs.authenticated="YES">
<!--- return role here, default role is always "user" --->
<cfset retargs.roles = "user">
</cfif>
<cfreturn retargs>
</cffunction>
Thanks for the help
You can use scope attribute of cfldap and set it to subtree:
It will allow search from the start entry and all levels below it.
I figured out the issue. I needed to add the scope of subtree, but also change the way the username was being authenicated from CN=something to an email address with the domain
Related
For several years, I have used dropdowns to determine the requirements for a SQL query and have never needed to use dropdowns with ‘related selects’ until now. I found a sample on how to do this and I can create related selects (with static data) which works well, see below using my data relating to vehicles and makes.
However, when I come to apply this to my environment, and use dynamic SQL query data, I cannot get it to work. I am confident that all the pieces of code are working together (as it works perfectly for the static data), but if I try and build the data automatically and then create the string to pass to the queryNew function, it fails.
This is the working Content.cfc file with STATIC query strings/data array
<cfcomponent>
<cfset tblMake = queryNew("name,id", "varchar,varchar", [{name:'RENAULT',id:'RENAULT'},{name:'RENAULT',id:'RENAULT'},{name:'RENAULT',id:'RENAULT'}])>
<cfset tblModel = queryNew("name,code,continent_id", "varchar,varchar,varchar", [{name:"TSERIES",code:"TSERIES",continent_id:"RENAULT"},{name:"MASTER",code:"MASTER",continent_id:"RENAULT"}])>
<cfset tblVoltage = queryNew("name,code", "varchar,varchar", [{name:"24 volt",code:"MASTER"},{name:"12 volt",code:"TSERIES"}])>
<cffunction name="getContent" access="remote" returntype="query" output="true">
<cfargument name="strTableName" type="string" required="true">
<cfargument name="strID" type="string" required="true">
<cfargument name="strName" type="string" required="true">
<cfargument name="intDistinct" type="numeric" required="false" default="0">
<cfargument name="selectedCol" type="string" required="false" default="0">
<cfargument name="selectedID" type="string" required="false" default="0">
<cfquery name="qryContent" dbtype="query">
select
<cfif arguments.intDistinct eq 1>distinct</cfif>
#arguments.strID# as theID,
#arguments.strName# as theValue
from #arguments.strTableName#
<cfif arguments.selectedID neq 0>
where #arguments.selectedCol# = '#arguments.selectedID#'
</cfif>
order by #arguments.strName#
</cfquery>
<cfreturn qryContent />
</cffunction>
</cfcomponent>
When I try and create the query using this method, nothing appears to work. I am looping through the database (from a query) and then creating a string using the required structure and the passing it to the function.
<cfcomponent>
<cfset XSTATIC = ""/>
<cfquery name="NOXVehicleModels" datasource="EBSNOX" >
SELECT DISTINCT VehicleMake
FROM [dbo].[NOX-Master]
WHERE VehicleMake IS NOT NULL
</cfquery>
<cfloop query="NOXVehicleModels">
<cfset XSTATIC = XSTATIC & "{name:'" & #Trim(NOXVehicleModels.VehicleMake)# & "',id:'"& #Trim(NOXVehicleModels.VehicleMake)# & "'},"/>
</cfloop>
<cfset XLEN=LEN(#XSTATIC#)/>
<cfset XSTATIC = MID(XSTATIC,1,XLEN-1)/>
<cfoutput>#XSTATIC#</cfoutput>
<cfset tblMake = queryNew("name,id", "varchar,varchar", [#XSTATIC#])>
I have created a separate cfoutput to test the string for structure etc and it appears to be correct, but it is just not passing to the querynew function. This is what the output looks like:-
{name:'CUMMINS',id:'CUMMINS'},{name:'DAF',id:'DAF'},{name:'IVECO',id:'IVECO'},{name:'MAN',id:'MAN'},{name:'MERCEDES',id:'MERCEDES'},{name:'RENAULT',id:'RENAULT'},{name:'SCANIA',id:'SCANIA'},{name:'VOLVO',id:'VOLVO'}
{name:'RENAULT',id:'RENAULT'},{name:'RENAULT',id:'RENAULT'},{name:'RENAULT',id:'RENAULT'}
What I have done so far:-
I have checked that the quotes are not important i.e. single/double.
I have tried to build the query outside of the tag.
Again, all appears (?) to be in order and I cannot understand that could be the problem. Possibly the structure is missing something before parsed to the function?
Any help would be greatly appreciated.
Thanks,
Jack
I am using CFLDAP to have users get authenticated using active directory. I am trying to write an if statement in case the users information does not come back as authenticated. I thought I could check by using <cfif AuthenticateUser.RecordCount gt 0> which is working as long as the information is correct but if the wrong information is entered and nothing is authenticated it is not running the else statement. Any help with this would be greatly appreciated!
<cfldap action="query"
name="AuthenticateUser"
attributes="dn,mail,givenname,sn,samaccountname,memberof"
start="DC=domain,DC=net"
filter="(&(objectclass=user)(samAccountName=#trim(form.user_name)#))"
server="servername"
Port="389"
username="tc\#trim(form.user_name)#"
password="#trim(form.user_pass)#">
<cfoutput>#AuthenticateUser.RecordCount#</cfoutput>
<!--- Get all records from the database that match this users credentials --->
<cfquery name="userVerify" datasource="test">
SELECT *
FROM dbo.Users
WHERE user_name = <cfqueryparam value="#AuthenticateUser.samaccountname#" cfsqltype="cf_sql_varchar" />
</cfquery>
<cfif AuthenticateUser.RecordCount gt 0>
<!--- This user has logged in correctly, change the value of the session.allowin value --->
<cfset session.allowin = "True" />
<cfset session.employee_number = userVerify.employee_number />
<!--- Now welcome user and redirect to "index.html" --->
<script>
self.location="../dashboard/dashboard.cfm";
</script>
<cfelse>
<!--- this user did not log in correctly, alert and redirect to the login page --->
<script>
alert("Your credentials could not be verified, please try again!");
self.location="Javascript:history.go(-1)";
</script>
</cfif>
I have also tried: <cfif len(AuthenticateUser)>
This is how I do it. I try to run a query against our domain using the supplied username and password. If the supplied username and password are not valid, an error is generated.
<cftry>
<cfldap action="Query"
name="ADResult"
attributes="dn"
start="DC=domain,DC=net"
filter="sAMAccountName=administrator"
server="servername"
scope = "subtree"
username="#arguments.username#"
password="#arguments.password#" />
<cfset isAuthenticated = true />
<cfcatch type="any">
<cfset isAuthenticated = false />
</cfcatch>
</cftry>
<cfreturn isAuthenticated />
I wrap this up in a function called "authenticate" and expose it via a web service that I call from my apps. If I then need additional details about the user (mail, givenName, etc), I have another function in the same web service that I will call after I am sure the user has been authenticated. Note that in this other function I'm using my administrator username and password to run the query.
<cfldap action="Query"
name="ADResult"
attributes="mail,givenName"
start="DC=domain,DC=net"
filter="sAMAccountName=#arguments.username#"
server="servername"
scope = "subtree"
username="administrator"
password="myAdminPassword" />
I take the results of this, populate a query object or a structure, and return that to the calling function.
So the entire process sort of looks like this:
<cfset objAD = createobject("webservice", "http://mywebservice.com") />
<cfset isAuthenticated = objAD.authenticate(form.username, form.password) />
<cfif isAuthenticated>
<cfset userDetails = objAD.getUserDetails(form.username)>
</cfif>
Hope this helps.
This is a formatted comment. You are trying to do too much at once. Go one step at a time. Start with this:
<cfdump var="before cfldap tag<br />">
<cfldap action="query"
name="AuthenticateUser"
etc
>
<cfdump var="after cfldap tag<br />">
<cfdump var = "#AuthenticateUser#">
<cfdump var="after cfdump<br />">
Run this code with both valid and not valid credentials. Look at what you get. React accordingly.
I think it throws an error when the query fails. Try this:
<cftry>
<cfldap action="query"
name="AuthenticateUser"
attributes="dn,mail,givenname,sn,samaccountname,memberof"
start="DC=domain,DC=net"
filter="(&(objectclass=user)(samAccountName=#trim(form.user_name)#))"
server="servername"
Port="389"
username="tc\#trim(form.user_name)#"
password="#trim(form.user_pass)#">
<cfset LoginStatus = "Success">
<cfcatch type="any">
<cfset LoginStatus = "Failed">
</cfcatch>
</cftry>
Then your cfif would be something like this:
<cfif LoginStatus eq "Success">
<!--- This user has logged in correctly, change the value of the session.allowin value --->
<cfset session.allowin = "True" />
<cfset session.employee_number = userVerify.employee_number />
<!--- Now welcome user and redirect to "index.html" --->
<script>
self.location="../dashboard/dashboard.cfm";
</script>
<cfelse>
<!--- this user did not log in correctly, alert and redirect to the login page --->
<script>
alert("Your credentials could not be verified, please try again!");
self.location="Javascript:history.go(-1)";
</script>
</cfif>
I think this works on CF9.
I have a web form which uses the action attribute to call a CFC like this:
<form action="mycfc.cfc?method=registeruser">
The CFC processes the data in the form and then I want it to return a variable telling the user if their form submission has been successful or not.
So within my CFC, I put this:
<cffunction name="registeruser" access="remote" hint="registers a new user" returnformat="JSON">
... PROCESSES FORM HERE THEN...
<cfset Msg = 'Success'>
<cfreturn Msg>
<cflocation url = "/registrationpage.cfm">
</cffunction>
How do I display the Msg variable in the registrationpage.cfm page? My output is set to JSON so I guess I have to DeSerialize but I have no idea how to actually reference/access this output from the method.
My whole answer is for educationnal purposes only and I strongly advise you to use an existing framework rather than reinventing the Wheels. Have a look at Picking a ColdFusion MVC Framework
You can store the value in the session scope. A lot of frameworks does it using a flash memory concept, which is a temporary memory (implemented as a struct) that destroys members when accessed.
Have a look at http://cfwheels.org/docs/1-1/chapter/using-the-flash it's quite straight forward to implement an API that does this.
Client code could look like (depending on your implementation):
<cfset session.flash.set('importantMsg', 'some important msg')>
<cflocation ...>
Then from the other page:
<cfif session.flash.has('importantMsg')>
<!--- The following line should also destroy the 'importantMsg' key --->
#session.flash.get('importantMsg')#
</cfif>
Here's an implementation example (not that the implementation is not thread-safe):
FlashMemory.cfc
<cfcomponent>
<cffunction name="init" returntype="FlashMemory">
<cfset variables.instance = {flash = {}}>
</cffunction>
<cffunction name="set" returntype="void">
<cfargument name="key" type="string" required="true">
<cfargument name="value" type="any" required="true">
<cfset variables.instance.flash[arguments.key] = arguments.value>
</cffunction>
<cffunction name="get" returntype="any">
<cfargument name="key" type="string" required="true">
<cfset var v = variables.instance.flash[arguments.key]>
<cfset structDelete(variables.instance.flash, arguments.key)>
<cfreturn v>
</cffunction>
<cffunction name="has" returntype="boolean">
<cfargument name="key" type="string" required="true">
<cfreturn structKeyExists(variables.instance.flash, arguments.key)>
</cffunction>
</cfcomponent>
onSessionStart
<cfset session.flash = new FlashMemory()>
Also please note that in your case, your remote CFC methods shouldn't return anything. You will use the flash memory to pass data around instead. That means when the method has finished it's work you can simply redirect the client.
You probably shouldn't use remote CFC methods in this particular case:
I have never really used remote CFC methods as stateful web services. The various advantages of remote CFC methods like their ability to spit out data in multiple data-interchange formats (JSON, WDDX...) is lost with your implementation.
You could simply do something like:
registration.cfm
<cfset errors = session.flash.get('registrationErrors')>
<cfif arrayLen(errors)>
<!--- Display errors --->
</cfif>
<form method="post" action="register.cfm">
...
</form>
register.cfm
<cfset registration = new Registration(argumentcollection = form)>
<cfset validator = new RegistrationValidator(registration)>
<cfif validator.validate()>
<cfset application.userService.register(registration)>
<!--- You can also redirect to a page that represents the correct state --->
<cflocation url="registered.cfm" addtoken="no">
<cfelse>
<!--- Store the errors collection in the flash memory --->
<cfset session.flash.set('registrationErrors', validator.errors())>
<!--- Redirect to the page the user came from --->
<cflocation url="#cgi.http_referer#" addtoken="no">
</cfif>
Take the cflocation tag out of your function. It will not execute anyway because it's after the cfreturn tag.
Also, post your form to a .cfm page, not the .cfc. From that .cfm page, do this:
<cfset MyObject = CreateObject(stuff for your cfc goes here)>
<cfset MessageFromFunction = MyObject.registeruser()>
<cfoutput>#MessageFromFunction</cfoutput.
I was wondering if someone can tell me what is wrong with this code because it doesn't work and it does not give me any errors either.
With this code I am trying to access a component that updates a DB table each time someone press on the link.
<cfajaxproxy bind="url:http://www.example.com/admin/CRM/linktracking.cfc" />
<cfscript>
SSLtype = (CGI.HTTPS EQ 'off')?'http://':'https://';
</cfscript>
<cfset domainname = CGI.SERVER_NAME>
<cfset domainURL = SSLtype&CGI.SERVER_NAME&CGI.SCRIPT_NAME&'?'&CGI.QUERY_STRING>
<script>
function insertTracking(href) {
var instance = new ajaxjsclass();
instance.setCallbackHandler();
<cfoutput>
instance.insertTrack(href,'#surveymain.contactid#','#domainname#','#domainURL#');
</cfoutput>
}
</script>
This is the component I am trying to access.
<cfcomponent>
<cffunction name="insertTrack" access="remote" returntype="void" >
<cfargument name="clickedURL" required="yes">
<cfargument name="contactid" required="yes">
<cfargument name="domainName" required="yes">
<cfargument name="domainURL" required="yes">
<cfquery name="q_inserttrack" datasource="dpsigweb">
update survey_tracking
set surveystarted = <cfqueryparam value="#now()#" cfsqltype="CF_SQL_TIMESTAMP">
where contactid= '#contactid#'
</cfquery>
<cfif ARGUMENTS.contactid NEQ ''>
<cfscript>
additionalInfo = '<b>Clicked URL</b> - <i>#ARGUMENTS.clickedURL#</i><br><br><b>From Site</b> - <i>#ARGUMENTS.domainURL#</i>';
gaCFC = CreateObject("component","mod_sigweb.components.guestaccount");
gaCFC.AddCorrespondenceCurDoctorProcedureRemote(
functionPassword = 'password',
contactid = '#ARGUMENTS.contactid#',
theMessage = additionalInfo,
statustype = 'Survey Started',
contactresult ='Survey Started'
);
</cfscript>
</cfif>
</cffunction>
</cfcomponent>
This is where I am trying to access the function from:
<a href="http://dev.example.com/surveys/survey.cfm?id=#id#&contactid=#contactid#&doctorid=#doctorid#" onClick="insertTracking(this.href)" >
I am suspecting that my <cfajaxproxy> tag may have a syntax error but when I am pressing the link I am not getting any errors.
I change my cfajaxproxy to this
<cfajaxproxy cfc="linktracking" jsclassname="ajaxjsclass" />
but still the function does not seem to work. I even moved the component and the cfm file in the same folder but it still doesn't work.
Edit:
I forgot to mention that i am sending this code in an email template. i don't know if that matters in any way. I created a test page that I am testing locally and my code works just fine. If there is something that I need to change because of that please let me know
Solution Found. I put the update query code directly on the page so when the user presses on the link and opens the page the query runs from there instead from the link.
The above code is working fine I just had issues with it because I was sending the page via email to the user. At least this is what I suspect.
I'm working with ColdFusion 9.0.1 and latest (for current date) stable build of twitter4j library - twitter4j-core-2.2.4. I'm trying to create functionality which allows users to login or register at our site using their twitter accounts.
I was able to create authorization part: user click on the link on our site and system redirects him to twitter page. On this page he able to "Authorise" our application. After that system redirecting him back using callBackURL.
But I have a problem with next step. When I'm trying to setOAuthAccessToken and for that trying to instantiate AccessToken object with follow part of code:
accessToken = createObject( 'java', 'twitter4j.auth.AccessToken' ).init( 'myStoredRequestToken', 'myStoredRequestTokenSecret' );
But I have follow error:
An exception occurred while instantiating a Java object. The class
must not be an interface or an abstract class. Error: ''.
Any ideas?
Update:
The start part of stacktrace:
'coldfusion.runtime.java.JavaObjectInstantiationException: Object instantiation exception. at coldfusion.runtime.java.JavaProxy.CreateObject(JavaProxy.java:171) at coldfusion.runtime.java.JavaProxy.invoke(JavaProxy.java:80) at coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2360) at cftwitter2ecfc2084917956$funcGETUSERCREDENTIALS.runFunction(C:\inetpub\wwwroot_test\twPlayGrnd_com\twitter.cfc:36) at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472) at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368) at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55) at ...
...cut here, not sure this is important...
the last part is
cfapplication2ecfc665259542$funcONREQUEST.runFunction(C:\inetpub\wwwroot_test\twPlayGrnd\application.cfc:55) ... 55 more Caused by: java.lang.IllegalArgumentException: Invalid access token format. at twitter4j.auth.AccessToken.(AccessToken.java:50) ... 60 more'
I saw the message about wrong format, but based on documentation at http://twitter4j.org it should accept two agruments (strings with keys). Am I wrong?
Update 2
*just find that out - I am sorry that I brought you into confusion with my first post and example... of course I used myStoredRequestToken, myStoredRequestTokenSecret, not a consumer key/secret *
*there are relevant parts of code I'm using for this functionality*
application.cfc ("onApplicationStart" function, instantiating components on start of application)
<cffunction name="onApplicationStart" access="public" returntype="boolean" output="false">
...
<cfset application.com.twitterInstance = server.javaloader.create("twitter4j.TwitterFactory").getInstance() />
<cfset application.com.twitter = createObject("component","_com.twitter").init() /> *<!--- cfc component which will be listed below --->*
...
</cffunction>
twitter.cfc (corresponding coldfusion component)
<cfcomponent displayname="twitter" output="false">
<cffunction name="init" access="public" output="false">
<cfreturn this>
</cffunction>
<cffunction name="authorizeTwitter" access="public" output="false">
<cfargument name="callBackURL" type="string" required="false" default="#request.twtCallBackURL#" />
<cfset var requestToken = "" />
<cfset application.com.twitterInstance.setOAuthConsumer(request.twtConsumerKey,request.twtConsumerSecret) />
<cfset requestToken = application.com.twitterInstance.getOAuthRequestToken(arguments.callBackURL) />
<cflock scope="session" type="exclusive" timeout="10">
<cfset session.oAuthRequestToken = requestToken.getToken()>
<cfset session.oAuthRequestTokenSecret = requestToken.getTokenSecret()>
</cflock>
<cflocation url="#vLocal.requestToken.getAuthorizationURL()#" addtoken="No" />
</cffunction>
<cffunction name="getUserCredentials" access="public" output="true">
<cfset var vLocal = {} />
<cfset vLocal.accessToken = "" />
<cfset vLocal.userData = "" />
<cfset vLocal.requestToken = "" />
<cfset vLocal.accessToken = server.javaloader.create("twitter4j.auth.AccessToken").init(session.oAuthRequestToken,session.oAuthRequestTokenSecret)>
<cfset application.com.twitterInstance.setOAuthAccessToken(vLocal.accessToken) />
<cfset vLocal.userData = application.com.twitterInstance.verifyCredentials() />
<cfdump var="#vLocal.userData#" label="User Credentials">
</cffunction>
First function is for first step - requesting twitter for autorization page (where user can autorize or deny application). Call back URL runs the page what calls the second function and I have problem only at this step (line for generation accessToken).
I have the same result if Im using createObject function instead of javaloader.
*So, my main question is still the same - to obtain the users unique Access Token? Please point me, what I'm doing wrong? What is a correct format for unique user's accessToken generation? Should I place oauth_verifier parameter there? if so, how?*
You are passing consumer key/secret instead of access token/secret.
You can generate your access token/secret at dev.twitter.com.
https://dev.twitter.com/apps » create my access token
Best,
Yusuke
I think I figured out what is wrong with the help of the examples 8. Sign in with Twitter and
Adding support for automated tweets with OAuth. Only tested with my own account though ..
Before you redirect to the authorization page, save the whole RequestToken object in a session variable. You will need it to extract the AccessToken. Note: I am storing the TwitterFactory in the application scope - not the instance
<cfset Twitter = application.TwitterFactory.getInstance()>
<cfset Twitter.setOAuthConsumer(application.TwitterConsumerKey, application.TwitterConsumerSecret)>
<cfset Session.RequestToken = Twitter.getOAuthRequestToken( YourCallBackURL )>
On callback, twitter adds a parameter named oauth_verifier to the URL. Use that value and the saved RequestToken to extract the AccessToken.
<cfset AccessToken = Twitter.getOAuthAccessToken(Session.RequestToken, URL.oauth_verifier)>
<cfset session.StoredAccessToken = AccessToken.getToken()>
<cfset session.StoredAccessSecret = AccessToken.getTokenSecret()>
Once you have the AccessToken/Secret you can access user details (update status,...) anywhere.
<cfset Twitter = application.TwitterFactory.getInstance()>
<cfset Twitter.setOAuthConsumer(application.TwitterConsumerKey,application.TwitterConsumerSecret)>
<cfset AccessToken = createObject("java", "twitter4j.auth.AccessToken")>
<cfset OAuthToken = AccessToken.init(session.StoredAccessToken, session.StoredAccessSecret)>
<cfset Twitter.setOAuthAccessToken(OAuthToken)>
<cfset userData = Twitter.verifyCredentials()>
<cfoutput>
id = #userData.getId()#<br>
name = #userData.getName()#<br>
followers = #userData.getFollowersCount()#<br>
friends = #userData.getFriendsCount()#<br>
</cfoutput>