Spring Security Facebook Authentication doesn't work - Internal Server error - facebook

I'm using Spring Security Facebook plugin in my grails app. It shows the below error messege when returning from facebook page after authentication. The facebook user details are not saved in database. Kindly help to solve this error and to authenticate facebook users successfully. Thanks in advance.
FacebookUser.groovy Domain Class
class FacebookUser {
long uid
String accessToken
Date accessTokenExpires
static belongsTo = [user: User]
static constraints = {
uid unique: true
}
}
Config.groovy settings for spring-security-facebook app
grails.plugins.springsecurity.facebook.domain.classname='com.awnsys.gcx.FacebookUser'
grails.plugins.springsecurity.facebook.domain.appUserConnectionPropertyName = 'user'
grails.plugins.springsecurity.facebook.appId='APPID'
grails.plugins.springsecurity.facebook.secret='secretID'
grails.plugins.springsecurity.facebook.autoCreate.enabled=true
grails.plugins.springsecurity.facebook.autoCreate.roles=['ROLE_USER', 'ROLE_FACEBOOK',]
Below is the error Message shown in browser when redirects from facebook after the user accepts app in facebook
Error 500: Internal Server Error
URI : /myapp/j_spring_security_facebook_check
Class : grails.validation.ValidationException
Message : Validation Error(s) occurred during save(): - Field error in object 'com.mydomain.myapp.User' on field 'username': rejected value [facebook_100005487962357]; codes [com.mydomain.myapp.User.username.email.error.com.mydomain.myapp.User.username,com.mydomain.myapp.User.username.email.error.username,com.mydomain.myapp.User.username.email.error.java.lang.String,com.mydomain.myapp.User.username.email.error,user.username.email.error.com.mydomain.myapp.User.username,user.username.email.error.username,user.username.email.error.java.lang.String,user.username.email.error,com.mydomain.myapp.User.username.email.invalid.com.mydomain.myapp.User.username,com.mydomain.myapp.User.username.email.invalid.username,com.mydomain.myapp.User.username.email.invalid.java.lang.String,com.mydomain.myapp.User.username.email.invalid,user.username.email.invalid.com.mydomain.myapp.User.username,user.username.email.invalid.username,user.username.email.invalid.java.lang.String,user.username.email.invalid,email.invalid.com.mydomain.myapp.User.username,email.invalid.username,email.invalid.java.lang.String,email.invalid]; arguments [username,class com.mydomain.myapp.User,facebook_100005487962357]; default message [Property [{0}] of class [{1}] with value [{2}] is not a valid e-mail address]
Around line 149 of DefaultFacebookAuthDao.groovy
146: appUser.setProperty(securityConf.userLookup.passwordExpiredPropertyName, false)
147: }
148: AppUserDomainClazz.withTransaction {
149: appUser.save(flush: true, failOnError: true)
150: }
151: }
152: user[appUserConnectionPropertyName] = appUser
Around line 148 of DefaultFacebookAuthDao.groovy
145: appUser.setProperty(securityConf.userLookup.accountLockedPropertyName, false)
146: appUser.setProperty(securityConf.userLookup.passwordExpiredPropertyName, false)
147: }
148: AppUserDomainClazz.withTransaction {
149: appUser.save(flush: true, failOnError: true)
150: }
151: }
Around line 67 of FacebookAuthProvider.groovy
64: log.error("Can't create user w/o access_token")
65: throw new CredentialsExpiredException("Can't receive access_token from Facebook")
66: }
67: user = facebookAuthDao.create(token)
68: justCreated = true
69: } else {
70: log.error "User $token.uid doesn't exist, and creation of a new user is disabled."
Around line 67 of FacebookAuthProvider.groovy
64: log.error("Can't create user w/o access_token")
65: throw new CredentialsExpiredException("Can't receive access_token from Facebook")
66: }
67: user = facebookAuthDao.create(token)
68: justCreated = true69: } else {
70: log.error "User $token.uid doesn't exist, and creation of a new user is disabled."
Trace
Line | Method
->> 149 | doCall in DefaultFacebookAuthDao.groovy
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 687 | withTransaction in org.grails.datastore.gorm.GormStaticApi
| 148 | create . . . . . . . in DefaultFacebookAuthDao.groovy
| 67 | authenticate in FacebookAuthProvider.groovy
| 40 | attemptAuthentication in FacebookAuthRedirectFilter.groovy
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . . . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 724 | run in java.lang.Thread

By default plugin generates username like facebook_%UID% (facebook_100005487962357 from your stacktrace). Seems that your User domain requires an email for .username field (and have such constraint), so it cannot be saved.
At this case I suggest you to implement own logic for filling User object, by implementing FacebookAuthService.createAppUser method. See docs: http://splix.github.io/grails-spring-security-facebook/guide/5%20Customization.html#5.1%20Using%20FacebookAuthService
And also, Facebook Authentication plugin don't know user email (it's not provided by Facebook Login by default), you have to fetch it from Facebook API, see example: https://github.com/splix/grails-facebook-authentication-example/blob/master/grails-app/services/FacebookAuthService.groovy#L51

For those who are implementing FacebookAuthService and having problems with Facebook and FacebookProfile classes being marked with error, make sure you added to your BuildConfig.groovy file the two plugins
compile ":spring-social-core:0.1.31"
compile ":spring-social-facebook:0.1.32"
NOTE: Spring Social Facebook is not the same plugin as Spring Security Facebook.
So if you have the lines above, you will still have to compile the Spring Social plugins.
compile ':spring-security-core:2.0-RC2'
compile ':spring-security-facebook:0.15.2-CORE2'

Related

RESTful client in Unity - validation error

I have a RESTful server created with ASP.Net and am trying to connect to it with the use of a RESTful client from Unity. GET works perfectly, however I am getting a validation error when sending a POST request. At the same time both GET and POST work when sending requests from Postman.
My Server:
[HttpPost]
public IActionResult Create(User user){
Console.WriteLine("***POST***");
Console.WriteLine(user.Id+", "+user.sex+", "+user.age);
if(!ModelState.IsValid)
return BadRequest(ModelState);
_context.Users.Add(user);
_context.SaveChanges();
return CreatedAtRoute("GetUser", new { id = user.Id }, user);
}
My client:
IEnumerator PostRequest(string uri, User user){
string u = JsonUtility.ToJson(user);
Debug.Log(u);
using (UnityWebRequest webRequest = UnityWebRequest.Post(uri, u)){
webRequest.SetRequestHeader("Content-Type","application/json");
yield return webRequest.SendWebRequest();
string[] pages = uri.Split('/');
int page = pages.Length - 1;
if (webRequest.isNetworkError || webRequest.isHttpError){
Debug.Log(pages[page] + ":\nReceived: " + webRequest.downloadHandler.text);
}
else{
Debug.Log(pages[page] + ":\nReceived: " + webRequest.downloadHandler.text);
}
}
}
I was trying both with the Json conversion and writing the string on my own, also with the WWWForm, but the error stays.
The error says that it's an unknown HTTP error. When printing the returned text it says:
"One or more validation errors occurred.","status":400,"traceId":"|b95d39b7-4b773429a8f72b3c.","errors":{"$":["'%' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0."]}}
On the server side it recognizes the correct method and controller, however, it doesn't even get to the first line of the method (Console.WriteLine). Then it says: "Executing ObjectResult, writing value of type 'Microsoft.AspNetCore.Mvc.ValidationProblemDetails'".
Here're all of the server side messages:
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 POST http://localhost:5001/user application/json 53
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint 'TheNewestDbConnect.Controllers.UserController.Create (TheNewestDbConnect)'
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[3]
Route matched with {action = "Create", controller = "User"}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult Create(TheNewestDbConnect.Data.Entities.User) on controller TheNewestDbConnect.Controllers.UserController (TheNewestDbConnect).
info: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[1]
Executing ObjectResult, writing value of type 'Microsoft.AspNetCore.Mvc.ValidationProblemDetails'.
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2]
Executed action TheNewestDbConnect.Controllers.UserController.Create (TheNewestDbConnect) in 6.680400000000001ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'TheNewestDbConnect.Controllers.UserController.Create (TheNewestDbConnect)'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished in 11.3971ms 400 application/problem+json; charset=utf-8
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
I have no idea what is happening and how to solve it. Any help will be strongly appreciated!
Turned out I was just missing an upload handler. Adding this line solved it: webRequest.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(JsonObject));

How to get the status of each line of a Datatable rows that is executed

Im testing a scenario where there are about 100s of username and password. I should use each username-password pair one by one and then try login to application. Then logout. Login again in the same browser without closing it. Here if any of the credentials are invalid then only that particular row should be marked fail and rest should continue execution
I tried to search for the solution but couldnot get any proper resolution
Scenario: To test if the given list of users credentials are valid
Given user is already at Login page
And user enters credentails
| Username | Password |
| user1 | password1 |
| user2 | invalid |
| user3 | password3 |
| user4 | password4 |
| user5 | password5 |
| user6 | password6 |
| user7 | password7 |
Here the status of 2nd row of datatable should be marked failed in the report and rest of the data should be executed except the failed ones. Passed data should be marked PASS in the report. How to achieve this.
First you would need to modify scenario as per below outline.
Scenario Outline: To test if the given list of users credentials are valid
Given user is already at Login page
And In credentails, user enters name as <Username> and Pwd as <Password>
Examples: Checking Login Scenarios
| Username | Password |
| user1 | password1 |
| user2 | invalid |
Second lets consider below is your step implementation
package my.package.name
import cucumber.api.PendingException;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.And;
import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;
#RunWith(Cucumber.class)
public class MyStepDefinitions {
#Given("^user is already at Login page$")
public void user_is_already_at_login_page() throws Throwable {
throw new PendingException();
}
#And("^In credentails, user enters name as (.+) and Pwd as (.+)$")
public void in_credentails_user_enters_name_as_and_pwd_as(String username, String password) throws Throwable {
throw new PendingException();
}
}
Third lets say under above step implementation, you write action to log into site and Action gets failed as Password was invalid. Now depending on which report you are using, you would need to write one method as per API of report, like i am sharing for extent.
public static synchronized void logFail(String message) {
try {
testReport.get().fail("<details>" + "<summary>" + "<b>" + "<font color=" + "red>" + "</font>" + "</b >" + "</summary>" + "<br>" + "<h6>" + "<b>" + BasePage.returnLocator(message) + "</b>"+ "</h6>" + "</br>" + message +"</details>"+" \n");
}
catch(Exception e) {
}
}
At last, following above hierarchy you would be able to print Passed/Failed in report.

couldnot get access token for daemon applications office 365

I have followed the blog http://blogs.msdn.com/b/exchangedev/archive/2015/01/22/building-demon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow.aspx to create a daemon application . I am able to get the app only token for the domain in which i have registered the application . But when I try to get for other organizations it throws an error
"
{"error":"invalid_client","error_description":"AADSTS70002: Error validating cre
dentials. AADSTS50012: Client assertion audience claim does not match Realm issu
er.\r\nTrace ID: 09e025f5-7db9-46c3-9df9-574c6820a011\r\nCorrelation ID: f4d0fa5
7-ee8c-4443-b28b-d372d945f81f\r\nTimestamp: 2015-05-04 13:51:51Z","error_codes":
[70002,50012],"timestamp":"2015-05-04 13:51:51Z","trace_id":"09e025f5-7db9-46c3-
9df9-574c6820a011","correlation_id":"f4d0fa57-ee8c-4443-b28b-d372d945f81f","subm
it_url":null,"context":null}"
But i have configured the application to be multi tenant .
this is the request i make
request https://login.windows.net/<tenantId>/oauth2/to
ken
grant_type=client_credentials
redirect_uri=http://localhost.com:9000
resource=https://outlook.office365.com/
client_assertion_type =urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion="eyJhbGciOiJSUzI1NiIsIng1dCI6IjZlLzEra01scHhuTHArZFJ4d1BqS21EdmZCQT0ifQ.eyJhdWQiOiJodHRwczovL2xvZ2luLndpbmRvd3MubmV0L2ZmNjQxNTFmLTIwM2EtNGM0MC1hZDcxLTExOTE2YjY2Yzg3My9vYXV0aDIvdG9rZW4iLCJleHAiOjE0MzEwMDYzMDMsImlzcyI6ImFkMTkzY2I1LWU2NmUtNDdmNS1iMTc4LTQxM2NlODA3ZDg2YiIsImp0aSI6IjMyMDZiYWI5LTVmYmUtNDA3ZS02OWY2LTJlNGRjNDQ3NzQxYSIsIm5iZiI6MTQzMTAxMTMwMywic3ViIjoiYWQxOTNjYjUtZTY2ZS00N2Y1LWIxNzgtNDEzY2U4MDdkODZiIn0.eEOlhsl-vbdzIiV3AfGFOH187Yb8zpGSGm6RbMhDX4NRJbwOWjJr3eFK3rGXSkl1vhSfJ_oFc69pB1AGfUK8u_SWRl7U3GgH3EJryE-FiVluCQ-ONZ3Qj1u6VggXgTodi0bdvhQF4WlwazXmJGbpeVRUZBm2rlTcd8JtQY96sOu1CRDpZJOFnHzjqleVdrnw8_pNVUafwlnaosRT9tOIgiK9apjN_KY5JMM1QTYKhKk5ZApjmr8agTZpObdz-_Y9znjaSxQcYkFnQeCGc-qwISzH1OqG_7JbCDq6Dp1-oBU5sJneJaF6IxX8-sWyaju3ntMWQyINeuHnRCoPrlp2tg"
this is the assertion i create
token.Header["alg"] = "RS256"
token.Header["x5t"] = "thumbprint of certificate "
token.Claims["aud"] = "https://login.windows.net/" + TenantId + "/oauth2/token"
token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
token.Claims["iss"] = client_id
token.Claims["jti"] = some guid
token.Claims["nbf"] = (time.Now().Add(time.Hour * 72).Unix()) + 5000
token.Claims["sub"] = client_id
please let me what to be done so that i can get the access token for other organiztion's domain .
Thanks in advance

How can I use a different email send method for the Accounts.sendEnrollmentEmail method in Meteor?

I use Mandrill to send emails from within Meteor. I don't have the default email method configured. I use this smart package https://github.com/Wylio/meteor-mandrill
Is there a way to change the Accounts.sendEnrollmentEmail method to use a smart package to send the email?
Right now I get the error below when I try to use that method.
Here is my error trace
message: Invalid login - 435 4.7.8 Error: authentication failed:
421 4.7.0 ip-10-102-139-231 Error: too many errors stack:
AuthError: Invalid login - 435 4.7.8 Error: authentication failed:
at Object.Future.wait (/Users/Bechard/.meteor/packages/meteor-tool/.1.0.36.15lvyk8++os.osx.x86_64+web.browser+web.cordova/meteor-tool-os.osx.x86_64/dev_bundle/lib/node_modules/fibers/future.js:326:15)
at smtpSend (packages/email/email.js:91)
at Object.Email.send (packages/email/email.js:168)
at Object.Email.send (packages/meteorhacks:kadira/lib/hijack/email.js:9)
at Object.Accounts.sendEnrollmentEmail (packages/accounts-password/password_server.js:460)
at Object.Utils.create_user (app/server/lib/globals.js:83:22)
at Meteor.methods.singleDonation (app/server/methods/donate.js:73:36)
at methodMap.(anonymous function) (packages/meteorhacks:kadira/lib/hijack/wrap_session.js:182)
at maybeAuditArgumentChecks (packages/ddp/livedata_server.js:1599)
at packages/ddp/livedata_server.js:648
- - - - -
421 4.7.0 ip-10-102-139-231 Error: too many errors
at SMTPClient._actionAUTHComplete (/Users/Bechard/.meteor/packages/email/.1.0.4.ioat51++os+web.browser+web.cordova/npm/node_modules/simplesmtp/lib/client.js:826:23)
at SMTPClient._onData (/Users/Bechard/.meteor/packages/email/.1.0.4.ioat51++os+web.browser+web.cordova/npm/node_modules/simplesmtp/lib/client.js:329:29)
at CleartextStream.emit (events.js:95:17)
at CleartextStream.<anonymous> (_stream_readable.js:748:14)
at CleartextStream.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:410:10)
at _stream_readable.js:403:7
at process._tickCallback (node.js:419:13)
Turns out I didn't declare the Mandrill key in my startup function.
I originally had this
Meteor.startup(function() {
return Meteor.Mandrill.config({
username: Meteor.settings.mandrillUsername
});
});
I changed it to this and the email sent fine.
Meteor.startup(function() {
return Meteor.Mandrill.config({
username: Meteor.settings.mandrillUsername,
"key": Meteor.settings.mandrillKey
});
});

Grails findAllByRole() error

I am trying to send email to all users with admin role when list() action has been called.
Inside my list method I put the following code:
def admins = User.findAllByRole("ROLE_ADMIN")
//def approverEmails = User.findByRole("ROLE_APPROVER").collect { it.email }
notifierService.sendApproverRequestEmail(admins)
flash.message = message(code: 'default.created.message', args: [message(code: 'project.label', default: 'Project'), projectInstance.id])
redirect(action: "show", id: projectInstance.id)
But Grails doesn't recognize findAllByRole() method. What am I doing wrong? Is there any other way to send message from service when certain actions in controller are called.
Here is also my service code:
def sendApprovalRequestEmail( def users ) {
users.each { -> user
mailService.sendMail{
to user.email
from "padre#everyonecounts.com"
subject "New project needs approval."
body "Hi ${user.username}! " +
"New project has been requested and needs your approval."
}
}
}
Here is the error:
URI
/PaDRe/project/list
Class
org.codehaus.groovy.grails.exceptions.InvalidPropertyException
Message
No property found for name [role] for class [class com.everyonecounts.padre.User]
Around line 21 of grails-app\controllers\com\everyonecounts\padre\ProjectController.groovy
18: params.max = Math.min(params.max ? params.int('max') : 10, 100)
19: [projectInstanceList: Project.list(params), projectInstanceTotal: Project.count()]
20:
21: def admins = User.findAllByRole("ROLE_ADMIN")
22: //def approverEmails = User.findByRole("ROLE_APPROVER").collect { it.email }
23: notifierService.sendApproverRequestEmail(admins)
24:
Trace
Line | Method
->> 108 | methodMissing in org.grails.datastore.gorm.GormStaticApi
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 21 | list in ProjectController.groovy
| 895 | runTask . . . in java.util.concurrent.ThreadPoolExecutor$Worker
| 918 | run in ''
^ 662 | run . . . . . in java.lang.Thread
Here is my User class
package com.everyonecounts.padre
class User{
transient springSecurityService
String username
String password
String email
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static constraints = {
username blank: false, unique: true
password size: 5..80, blank: false
}
static mapping = {
password column: '`password`'
}
Set<Role> getAuthorities() {
UserRole.findAllByUser(this).collect { it.role } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
The problem you are having is because you don't understand the default spring security implementation. To get a list of users with a given role:
UserRole.findAllByRole(Role.findByAuthority("ROLE_ADMIN"))*.user
Your problem probably is that User.findAllByRole() is expecting a Role as the argument, not a String.
There is a relevant example in 'Querying Associations' subsection of http://grails.org/doc/2.2.x/guide/single.html#finders (shown below)
def author = Author.findByName("Stephen King")
def books = author ? Book.findAllByAuthor(author) : []