Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PrepareResponse().AsActionResult() throws unsupported exception DotNetOpenAuth CTP

Currently I'm developing an OAuth2 authorization server using DotNetOpenAuth CTP version. My authorization server is in asp.net MVC3, and it's based on the sample provided by the library. Everything works fine until the app reaches the point where the user authorizes the consumer client.

There's an action inside my OAuth controller which takes care of the authorization process, and is very similar to the equivalent action in the sample:

[Authorize, HttpPost, ValidateAntiForgeryToken]
    public ActionResult AuthorizeResponse(bool isApproved)
    {
        var pendingRequest = this.authorizationServer.ReadAuthorizationRequest();

        if (pendingRequest == null)
        {
            throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request.");
        }

        IDirectedProtocolMessage response;
        if (isApproved)
        {
            var client = MvcApplication.DataContext.Clients.First(c => c.ClientIdentifier == pendingRequest.ClientIdentifier);
            client.ClientAuthorizations.Add(
                new ClientAuthorization
                {
                    Scope = OAuthUtilities.JoinScopes(pendingRequest.Scope),
                    User = MvcApplication.LoggedInUser,
                    CreatedOn = DateTime.UtcNow,
                });
            MvcApplication.DataContext.SaveChanges();
            response = this.authorizationServer.PrepareApproveAuthorizationRequest(pendingRequest, User.Identity.Name);
        }
        else
        {
            response = this.authorizationServer.PrepareRejectAuthorizationRequest(pendingRequest);
        }

        return this.authorizationServer.Channel.PrepareResponse(response).AsActionResult();
    }

Everytime the program reaches this line:

this.authorizationServer.Channel.PrepareResponse(response).AsActionResult();

The system throws an exception which I have researched with no success. The exception is the following: Only parameterless constructors and initializers are supported in LINQ to Entities.

The stack trace: http://pastebin.com/TibCax2t

The only thing I've done differently from the sample is that I used entity framework's code first approach, an I think the sample was done using a designer which autogenerated the entities.

Thank you in advance.

like image 221
Daniel Avatar asked Dec 13 '11 22:12

Daniel


2 Answers

If you started from the example, the problem Andrew is talking about stays in DatabaseKeyNonceStore.cs. The exception is raised by one on these two methods:

    public CryptoKey GetKey(string bucket, string handle) {
        // It is critical that this lookup be case-sensitive, which can only be configured at the database.
        var matches = from key in MvcApplication.DataContext.SymmetricCryptoKeys
                      where key.Bucket == bucket && key.Handle == handle
                      select new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc());

        return matches.FirstOrDefault();
    }

    public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) {
        return from key in MvcApplication.DataContext.SymmetricCryptoKeys
               where key.Bucket == bucket
               orderby key.ExpiresUtc descending
               select new KeyValuePair<string, CryptoKey>(key.Handle, new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc()));
    }

I've resolved moving initializations outside of the query:

    public CryptoKey GetKey(string bucket, string handle) {
        // It is critical that this lookup be case-sensitive, which can only be configured at the database.
        var matches = from key in db.SymmetricCryptoKeys
                      where key.Bucket == bucket && key.Handle == handle
                      select key;

        var match = matches.FirstOrDefault();

        CryptoKey ck = new CryptoKey(match.Secret, match.ExpiresUtc.AsUtc());

        return ck;
    }

    public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) {
        var matches = from key in db.SymmetricCryptoKeys
               where key.Bucket == bucket
               orderby key.ExpiresUtc descending
               select key;

        List<KeyValuePair<string, CryptoKey>> en = new List<KeyValuePair<string, CryptoKey>>();

        foreach (var key in matches)
            en.Add(new KeyValuePair<string, CryptoKey>(key.Handle, new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc())));

        return en.AsEnumerable<KeyValuePair<string,CryptoKey>>();
    }

I'm not sure that this is the best way, but it works!

like image 110
Lorenzo Avatar answered Nov 08 '22 05:11

Lorenzo


It looks like your ICryptoKeyStore implementation may be attempting to store CryptoKey directly, but it's not a class that is compatible with the Entity framework (due to not have a public default constructor). Instead, define your own entity class for storing the data in CryptoKey and your ICryptoKeyStore is responsible to transition between the two data types for persistence and retrieval.

like image 1
Andrew Arnott Avatar answered Nov 08 '22 05:11

Andrew Arnott