Friday, March 2, 2012
Apache Santuario (XML Security for Java) 1.5.1 released
Apache Santuario (XML Security for Java) 1.5.1 has been released and is available for download. The release notes are available here. This release fixes two important bugs - a bug in XMLSignatureInput when
using a BufferedInputStream, as well as a bug which caused 1.5.0 to
continue to require Xalan. It also contains some performance
improvements for encryption and decryption.
Wednesday, February 22, 2012
WS-Trust SPNego support in Apache CXF
Support for SPNego using WS-Trust has been added to Apache CXF and will be available in the forthcoming 2.4.7 and 2.5.3 releases. This new functionality allows a CXF client to integrate with WCF 4.0, as WCF 4.0 uses message level NTLM/Kerberos based on SPNego using WS-Trust. See the following blog for an in-depth explanation of how to do exactly this. Support for obtaining and validating SPNEGO tokens was added to Apache WSS4J in the 1.6.4 release. WSS4J 1.6.5 will feature support for making the Spnego Client and Service Action classes pluggable, so that the
user can specify a custom means of obtaining the ticket.
Using WS-Trust for SPNego is described in the following application note. The client contacts a KDC and obtains a SP Negotiation token, which it sends to the service provider via WS-Trust. If the negotiation is incomplete, the service provider can respond to the client to continue the negotiation. Once the negotiation is complete, a WS-Trust RequestedProofToken is created which contains a secret key that has been encrypted with the negotiated key, and this is returned to the client along with an Authenticator and a SecurityContextToken. The client can decrypt the EncryptedKey, and use this key with a symmetric encryption or signature algorithm to secure a request.
Note that the focus is on making sure that a CXF client can interoperate with WCF, and hence the STS support for SPNego is only intended as a means of testing the client code. In particular, the STS does not return an Authenticator, which is required by the spec. One additional limitation is that the STS client does not currently support continued negotation.
1) Running the WS-Trust SPNego system tests in Apache CXF
To run the WS-Trust SPNego system tests in CXF, it is first necessary to set up a KDC correctly. Follow the instructions given in section 1 in a previous blog post which describes how to run the Kerberos system tests in CXF. Next, make sure that the JDK has unlimited security policies installed, and then checkout the CXF trunk via:
mvn test -Dtest=SpnegoTokenTest -Djava.security.auth.login.config=src/test/resources/kerberos.jaas
1.1) WS-SecurityPolicy configuration
The wsdl that defines the service endpoints contains WS-SecurityPolicy expressions that define the security requirements of the endpoints. The following security policies are used for the tests:
Both the CXF client and service endpoint use JAAS to authenticate to the KDC. The JAAS file used as part of the system test is passed to the tests via the System property "java.security.auth.login.config". The client (alice) uses the following login module:
Both the service and client endpoints are spring-loaded. The contain the following JAX-WS properties, which are defined in SecurityConstants:
Using WS-Trust for SPNego is described in the following application note. The client contacts a KDC and obtains a SP Negotiation token, which it sends to the service provider via WS-Trust. If the negotiation is incomplete, the service provider can respond to the client to continue the negotiation. Once the negotiation is complete, a WS-Trust RequestedProofToken is created which contains a secret key that has been encrypted with the negotiated key, and this is returned to the client along with an Authenticator and a SecurityContextToken. The client can decrypt the EncryptedKey, and use this key with a symmetric encryption or signature algorithm to secure a request.
Note that the focus is on making sure that a CXF client can interoperate with WCF, and hence the STS support for SPNego is only intended as a means of testing the client code. In particular, the STS does not return an Authenticator, which is required by the spec. One additional limitation is that the STS client does not currently support continued negotation.
1) Running the WS-Trust SPNego system tests in Apache CXF
To run the WS-Trust SPNego system tests in CXF, it is first necessary to set up a KDC correctly. Follow the instructions given in section 1 in a previous blog post which describes how to run the Kerberos system tests in CXF. Next, make sure that the JDK has unlimited security policies installed, and then checkout the CXF trunk via:
svn co https://svn.apache.org/repos/asf/cxf/trunk/Go into the "trunk" directory, and compile and install CXF via "mvn -Pfastinstall" (this will avoid running tests). Finally go into the WS-Security system tests in "systests/ws-security". The SpnegoTokenTest contains two tests, which are @Ignore'd by default. Open SpnegoTokenTest.java and comment out the "@org.junit.Ignore" entries for both tests. If you want to see the message exchanges, open src/test/resources/logging.properties, and change the level from WARNING to INFO, and the ConsoleHandler level from SEVERE to INFO. Finally, run the tests via:
mvn test -Dtest=SpnegoTokenTest -Djava.security.auth.login.config=src/test/resources/kerberos.jaas
1.1) WS-SecurityPolicy configuration
The wsdl that defines the service endpoints contains WS-SecurityPolicy expressions that define the security requirements of the endpoints. The following security policies are used for the tests:
- DoubleItSpnegoSymmetricProtectionPolicy: This uses a Symmetric binding, where the protection token is a SpnegoContextToken.
- DoubleItSpnegoSymmetricProtectionDerivedPolicy: This uses a Symmetric binding, where the protection token is key derived from a SpnegoContextToken.
Both the CXF client and service endpoint use JAAS to authenticate to the KDC. The JAAS file used as part of the system test is passed to the tests via the System property "java.security.auth.login.config". The client (alice) uses the following login module:
alice {and the service endpoint (bob) uses:
com.sun.security.auth.module.Krb5LoginModule required
refreshKrb5Config=true useKeyTab=true keyTab="/etc/alice.keytab"
principal="alice";
};
bob {1.3) Client and Service endpoint configuration
com.sun.security.auth.module.Krb5LoginModule required
refreshKrb5Config=true useKeyTab=true storeKey=true
keyTab="/etc/bob.keytab" principal="bob/service.ws.apache.org";
};
Both the service and client endpoints are spring-loaded. The contain the following JAX-WS properties, which are defined in SecurityConstants:
- "ws-security.kerberos.jaas.context" - This refers to the JAAS context given in the configuration file above. The clients use a value of "alice", and the service endpoints use "bob".
- "ws-security.kerberos.spn"- This is only configured on the client side, and specifies the Kerberos Service Provider Name ("bob@service.ws.apache.org").
- "ws-security.spnego.client.action" - The SpnegoClientAction implementation to use for SPNEGO. This allows the user to plug in a different implementation to obtain a service ticket. See here for more details on how to use this property.
Tuesday, January 24, 2012
Apache Santuario (XML Security for Java) 1.5.0 released
Apache Santuario (XML Security for Java) 1.5.0 has been released. It can be downloaded here. Please read the release notes (collated from my previous blog entries) if you are planning to upgrade.
Friday, January 13, 2012
Apache Santuario (XML Security for Java) 1.5.0 RC2
I posted a RC1 for Apache Santuario (XML Security for Java) almost a month ago now. Since then, a large number of changes have been made to address some inconsistencies in RC1 as well to add some new functionality. The RC2 release is available here. Please download it and post any issues that are found to the mailing list. The changes compared to the RC1 release (documented here) are as follows:
1) Support for RSA-OAEP key transport algorithms with strong digests
The 1.4.x releases only support using SHA-1 with the RSA-OAEP key transport algorithm for encryption and decryption. The 1.5.0 RC2 release supports stronger digests using the ds:DigestMethod child of xenc:EncrytionMethod. In addition, it fully supports the xenc11:MGF Algorithm as documented in the XML Encryption 1.1 specification.
To test this functionality, all of the XML Encryption 1.1 Key Wrapping test-cases have been implemented, both for encryption and decryption. These tests also serve to better test the support for GCM algorithms in the 1.5.0 release. Support for 192 bit AES-GCM was added as part of this work.
2) Major changes to how Elements are resolved
The release notes for RC1 described how the IdResolver no longer searches the current Document for an Element matching the requested Id in certain "known" namespaces, and instead how it was the responsibility of the user to register Elements by Id in the IdResolver (or via setIdAttributeNS if using the JSR-105 API), if they are required as part of the signature validation process.
In RC2, the static cache of Id->Elements that was maintained in the IdResolver has been removed. Instead, the ResourceResolver implementations that are responsible for resolving same-Document URI references resolve Elements by querying Document.getElementById(). The IdResolver has been deprecated, so that it is no longer possible to register an Element by Id, and the "get" methods simply delegate to the DOM call above.
So what does this mean for the user? The user is now responsible for registering any same-Document Elements by Id, which must be resolved as part of the signature creation/validation process. This can be done in two ways:
A Signature Wrapping attack can occur when a malicious entity duplicates some signed Element in a document, and then modifies the content of the duplicated Element, but keeps the same Id. If the signature validation process only finds the initial Element, then signature validation will pass, and the user might be fooled into thinking that the modified Element has been signed, as it has the same Id as the original validated Element.
The implication of this attack is that it is vital that the user checks that the Elements that were signed correspond to the Elements that he/she expects to be signed. In other words, the Elements that were signed should be located in a specific "known" place in the Document. The best way of facilitating this check is to make sure that the signature validation process returns the Elements that it validated. The JSR-105 API supports this via the "javax.xml.crypto.dsig.cacheReference" boolean property, that can be set on the context.
However, the older XMLSignature, which pre-dates the JSR-105 API, did not include this functionality. This has been fixed in the RC2 release, e.g.:
XMLSignature signature = ...
// Perform validation and then...
SignedInfo signedInfo = signature.getSignedInfo();
for (int i = 0; i < signedInfo.getLength(); i++) {
Reference reference = signedInfo.item(i);
ReferenceData refData = reference.getReferenceData();
....
}
ReferenceData is a new interface that duplicates the way the JSR-105 API returns references. Three different implementations have been provided depending on whether the dereferenced Element is a NodeSet, Element or OctetStream.
Finally, some new functionality has been added when secure validation is enabled, to ensure that when an Element is de-referenced via Document.getElementById() (as described above), no other Element in the tree has an Attribute that is also registered as an Id with the same value. This is done via a tree search, and guarantees that the Element retrieved via the getElementById call is unique in the Document (something that is not guaranteed by the contract of getElementById). However note that another Element could still exist in the tree with a matching Id in another namespace.
1) Support for RSA-OAEP key transport algorithms with strong digests
The 1.4.x releases only support using SHA-1 with the RSA-OAEP key transport algorithm for encryption and decryption. The 1.5.0 RC2 release supports stronger digests using the ds:DigestMethod child of xenc:EncrytionMethod. In addition, it fully supports the xenc11:MGF Algorithm as documented in the XML Encryption 1.1 specification.
To test this functionality, all of the XML Encryption 1.1 Key Wrapping test-cases have been implemented, both for encryption and decryption. These tests also serve to better test the support for GCM algorithms in the 1.5.0 release. Support for 192 bit AES-GCM was added as part of this work.
2) Major changes to how Elements are resolved
The release notes for RC1 described how the IdResolver no longer searches the current Document for an Element matching the requested Id in certain "known" namespaces, and instead how it was the responsibility of the user to register Elements by Id in the IdResolver (or via setIdAttributeNS if using the JSR-105 API), if they are required as part of the signature validation process.
In RC2, the static cache of Id->Elements that was maintained in the IdResolver has been removed. Instead, the ResourceResolver implementations that are responsible for resolving same-Document URI references resolve Elements by querying Document.getElementById(). The IdResolver has been deprecated, so that it is no longer possible to register an Element by Id, and the "get" methods simply delegate to the DOM call above.
So what does this mean for the user? The user is now responsible for registering any same-Document Elements by Id, which must be resolved as part of the signature creation/validation process. This can be done in two ways:
- Using the DOM APIs: Element.setIdAttribute*
- Using the JSR-105 API: DOMCryptoContext.setIdAttributeNS
A Signature Wrapping attack can occur when a malicious entity duplicates some signed Element in a document, and then modifies the content of the duplicated Element, but keeps the same Id. If the signature validation process only finds the initial Element, then signature validation will pass, and the user might be fooled into thinking that the modified Element has been signed, as it has the same Id as the original validated Element.
The implication of this attack is that it is vital that the user checks that the Elements that were signed correspond to the Elements that he/she expects to be signed. In other words, the Elements that were signed should be located in a specific "known" place in the Document. The best way of facilitating this check is to make sure that the signature validation process returns the Elements that it validated. The JSR-105 API supports this via the "javax.xml.crypto.dsig.cacheReference" boolean property, that can be set on the context.
However, the older XMLSignature, which pre-dates the JSR-105 API, did not include this functionality. This has been fixed in the RC2 release, e.g.:
XMLSignature signature = ...
// Perform validation and then...
SignedInfo signedInfo = signature.getSignedInfo();
for (int i = 0; i < signedInfo.getLength(); i++) {
Reference reference = signedInfo.item(i);
ReferenceData refData = reference.getReferenceData();
....
}
ReferenceData is a new interface that duplicates the way the JSR-105 API returns references. Three different implementations have been provided depending on whether the dereferenced Element is a NodeSet, Element or OctetStream.
Finally, some new functionality has been added when secure validation is enabled, to ensure that when an Element is de-referenced via Document.getElementById() (as described above), no other Element in the tree has an Attribute that is also registered as an Id with the same value. This is done via a tree search, and guarantees that the Element retrieved via the getElementById call is unique in the Document (something that is not guaranteed by the contract of getElementById). However note that another Element could still exist in the tree with a matching Id in another namespace.
Apache CXF 2.5.1 STS updates
Last year I wrote a series of blog posts (starting here) documenting the Security Token Service (STS) implementation included as part of Apache CXF 2.5.0. Apache CXF 2.5.1 was released
a few weeks ago, and includes a number of bug fixes and improvements to
the STS. In this post I'll document the more important changes.
1) Support to configure keystores per SAML realm
In CXF 2.5.0 it was possible to sign an issued SAML Token using a different private key per realm, by setting the "signatureAlias" property of the SAMLRealm class. However, the signature alias is used with a single KeyStore, which is shared across all realms. This problem has been fixed in CXF 2.5.1, where it is now possible to also configure a keystore to use per-realm.
2) Support to handle claims per realm
In CXF 2.5.1 support has been added to handle claims per-realm. The ClaimsHandler interface has been updated to so that the current realm and WebServiceContext object are available when retrieving claim values. This means that any custom ClaimsHandler implementation based on CXF 2.5.0 must be updated to reflect the changed method signature.
3) Support validating a token per realm
In CXF 2.5.0 the current realm is ignored when validating a token. In CXF 2.5.1, support has been added to include the current realm when querying a TokenValidator implementation to see if it can "handle" a given token. In addition, all TokenValidator implementations that ship with the STS return a Principal as part of the TokenValidatorResponse object, regardless of whether validation was successful or not.
4) OnBehalfOf Token Validation
In CXF 2.5.0 the responsibility for validating "OnBehalfOf" tokens was delegated to the TokenProvider implementation. In CXF 2.5.1, OnBehalfOf Token Validation has been moved to the TokenIssueOperation, and so OnBehalfOf Tokens are validated for all subsequent TokenProviders. This validation is achieved by querying a list of TokenValidator implementations to see if any can validate the received token. If validation is successful, then the state of the ReceivedToken (VALID, INVALID, NONE) is updated to reflect this. If no TokenValidator implementation exists that can validate the OnBehalfOf token, then the token has a state set to INVALID. Identity Mapping also now applies to the (VALID) OnBehalfOf Token.
5) Support for OnBehalfOf in the SAMLTokenProvider
In CXF 2.5.0, the SAMLTokenProvider can issue a SAML token based on the authenticated principal associated with the request, e.g. the principal associated with the security token in the WS-Security header. It does not support the scenario that a client is requesting a SAML token "OnBehalfOf" another SAML Token, in other words that the principal name associated with the "OnBehalfOf" token is used as the subject name of the issued SAML token. This functionality has been added in CXF 2.5.1.
6) Validate SAML Conditions against the current time
Support has been added to validate the Conditions of a received SAML Token against the current time.
1) Support to configure keystores per SAML realm
In CXF 2.5.0 it was possible to sign an issued SAML Token using a different private key per realm, by setting the "signatureAlias" property of the SAMLRealm class. However, the signature alias is used with a single KeyStore, which is shared across all realms. This problem has been fixed in CXF 2.5.1, where it is now possible to also configure a keystore to use per-realm.
2) Support to handle claims per realm
In CXF 2.5.1 support has been added to handle claims per-realm. The ClaimsHandler interface has been updated to so that the current realm and WebServiceContext object are available when retrieving claim values. This means that any custom ClaimsHandler implementation based on CXF 2.5.0 must be updated to reflect the changed method signature.
3) Support validating a token per realm
In CXF 2.5.0 the current realm is ignored when validating a token. In CXF 2.5.1, support has been added to include the current realm when querying a TokenValidator implementation to see if it can "handle" a given token. In addition, all TokenValidator implementations that ship with the STS return a Principal as part of the TokenValidatorResponse object, regardless of whether validation was successful or not.
4) OnBehalfOf Token Validation
In CXF 2.5.0 the responsibility for validating "OnBehalfOf" tokens was delegated to the TokenProvider implementation. In CXF 2.5.1, OnBehalfOf Token Validation has been moved to the TokenIssueOperation, and so OnBehalfOf Tokens are validated for all subsequent TokenProviders. This validation is achieved by querying a list of TokenValidator implementations to see if any can validate the received token. If validation is successful, then the state of the ReceivedToken (VALID, INVALID, NONE) is updated to reflect this. If no TokenValidator implementation exists that can validate the OnBehalfOf token, then the token has a state set to INVALID. Identity Mapping also now applies to the (VALID) OnBehalfOf Token.
5) Support for OnBehalfOf in the SAMLTokenProvider
In CXF 2.5.0, the SAMLTokenProvider can issue a SAML token based on the authenticated principal associated with the request, e.g. the principal associated with the security token in the WS-Security header. It does not support the scenario that a client is requesting a SAML token "OnBehalfOf" another SAML Token, in other words that the principal name associated with the "OnBehalfOf" token is used as the subject name of the issued SAML token. This functionality has been added in CXF 2.5.1.
6) Validate SAML Conditions against the current time
Support has been added to validate the Conditions of a received SAML Token against the current time.
Tuesday, December 20, 2011
WS-SecurityPolicy Examples in Apache CXF
The OASIS WS-SecurityPolicy Examples Version 1.0 specification gives a set of example policies for standard security deployments, as well as the corresponding message exchanges generated by those policies. The policies in the spec cover UsernameTokens, X509 Tokens, SAML Tokens and SecureConversation, used in conjunction with various security bindings (symmetric/asymmetric/transport).
I have implemented a set of system tests in Apache CXF that use these policies with a standard "double it" web service invocation. All of the policies in the specification are covered, apart from 2.2.2.1 which is an uncommon use-case of using an IssuedToken policy to reference an agreed out-of-band token.
The example tests are a good way of understanding how to implement and use various security policies. Here are links to the various tests and WSDLs which include the corresponding security policies:
I have implemented a set of system tests in Apache CXF that use these policies with a standard "double it" web service invocation. All of the policies in the specification are covered, apart from 2.2.2.1 which is an uncommon use-case of using an IssuedToken policy to reference an agreed out-of-band token.
The example tests are a good way of understanding how to implement and use various security policies. Here are links to the various tests and WSDLs which include the corresponding security policies:
Monday, December 19, 2011
Apache Santuario (XML Security for Java) 1.5.0 RC1
A release candidate for Apache Santuario (XML Security for Java) 1.5.0 has been published. Please download it and post any issues that are found to the mailing list. The 1.5.0 release is not binary compatible with the 1.4.x code due to extensive refactoring. Some of the more significant changes are as follows:
1) JDK 1.4.x support dropped
The 1.5.0 release drops support for JDK 1.4.x (see here and here). The APIs have been updated to use generics where possible.
2) Xalan is no longer a required dependency
Xalan/Xerces/Xml-apis are now optional dependencies, and have been marked as such in the pom. These libraries are only required if you want to support the XPath here() function, which is not supported by the XPath API in the JDK.
3) GCM support added
Support for GCM algorithms has been added via a third-party provider. See here for an example of how this is done in Apache WSS4J via BouncyCastle.
4) JSR-105 provider has been renamed
The Santuario JSR-105 provider "org.jcp.xml.dsig.internal.XMLDSigRI" has been renamed as "org.apache.jcp.xml.dsig.internal.XMLDSigRI". This is to avoid conflict with the JDK provider of the same name. In addition, the XMLDSigRI provider's name has changed from "XMLDSig" to "ApacheXMLDSig". See here for more details.
Please note that it won't be possible to drop in the xmlsec.jar in the endorsed directory anymore and expect it to override the JDK's JSR 105 provider. You will need to edit the java.security file to register the new provider, or hard-code the provider name in your application code.
5) Secure Validation property
A new property has been added to enable "secure validation". This property is false by default. When set to true, it enforces the following processing rules:
XMLValidateContext context = new DOMValidateContext(key, elem);
context.setProperty("org.apache.jcp.xml.dsig.secureValidation", Boolean.TRUE);
6) Dynamic registration of default algorithms
The 1.4.x release loads all supported algorithms/implementations by reading and parsing an xml configuration file. This gives the user the power to override the default configuration file by setting the appropriate system property, and to add/remove algorithms as desired.
The downside to the current configuration approach is the performance issue of reading a file from the filesystem, parsing it, and then class-loading all of the implementations. Given that the majority of users probably just use the default algorithms that come with the library, this represents a performance issue on start-up.
In 1.5.0, the default algorithms are loaded dynamically. To revert to the older behaviour of loading algorithms from a properties file then set the System property "org.apache.xml.security.resource.config" to point to the file.
7) The IdResolver no longer searches for Elements in "known" namespaces
The IdResolver class is responsible for retrieving Elements for a given Id. In the 1.5.0 release it will no longer attempt to search the current Document for an Element matching the requested Id in certain "known" namespaces (e.g. SOAP Message Security). It is the responsibility of the user to register Elements by Id in the IdResolver, if they are required as part of the signature validation process. This can be done via the "setIdAttributeNS" method in the DOMCryptoContext for users of the JSR-105 API.
1) JDK 1.4.x support dropped
The 1.5.0 release drops support for JDK 1.4.x (see here and here). The APIs have been updated to use generics where possible.
2) Xalan is no longer a required dependency
Xalan/Xerces/Xml-apis are now optional dependencies, and have been marked as such in the pom. These libraries are only required if you want to support the XPath here() function, which is not supported by the XPath API in the JDK.
3) GCM support added
Support for GCM algorithms has been added via a third-party provider. See here for an example of how this is done in Apache WSS4J via BouncyCastle.
4) JSR-105 provider has been renamed
The Santuario JSR-105 provider "org.jcp.xml.dsig.internal.XMLDSigRI" has been renamed as "org.apache.jcp.xml.dsig.internal.XMLDSigRI". This is to avoid conflict with the JDK provider of the same name. In addition, the XMLDSigRI provider's name has changed from "XMLDSig" to "ApacheXMLDSig". See here for more details.
Please note that it won't be possible to drop in the xmlsec.jar in the endorsed directory anymore and expect it to override the JDK's JSR 105 provider. You will need to edit the java.security file to register the new provider, or hard-code the provider name in your application code.
5) Secure Validation property
A new property has been added to enable "secure validation". This property is false by default. When set to true, it enforces the following processing rules:
- Limits the number of Transforms per Reference to a maximum of 5.
- Does not allow XSLT transforms.
- Does not allow a RetrievalMethod to reference another RetrievalMethod.
- Does not allow a Reference to call the ResolverLocalFilesystem or the ResolverDirectHTTP (references to local files and HTTP resources are forbidden).
- Limits the number of references per Manifest (SignedInfo) to a maximum of 30.
- MD5 is not allowed as a SignatureAlgorithm or DigestAlgorithm.
XMLValidateContext context = new DOMValidateContext(key, elem);
context.setProperty("org.apache.jcp.xml.dsig.secureValidation", Boolean.TRUE);
6) Dynamic registration of default algorithms
The 1.4.x release loads all supported algorithms/implementations by reading and parsing an xml configuration file. This gives the user the power to override the default configuration file by setting the appropriate system property, and to add/remove algorithms as desired.
The downside to the current configuration approach is the performance issue of reading a file from the filesystem, parsing it, and then class-loading all of the implementations. Given that the majority of users probably just use the default algorithms that come with the library, this represents a performance issue on start-up.
In 1.5.0, the default algorithms are loaded dynamically. To revert to the older behaviour of loading algorithms from a properties file then set the System property "org.apache.xml.security.resource.config" to point to the file.
7) The IdResolver no longer searches for Elements in "known" namespaces
The IdResolver class is responsible for retrieving Elements for a given Id. In the 1.5.0 release it will no longer attempt to search the current Document for an Element matching the requested Id in certain "known" namespaces (e.g. SOAP Message Security). It is the responsibility of the user to register Elements by Id in the IdResolver, if they are required as part of the signature validation process. This can be done via the "setIdAttributeNS" method in the DOMCryptoContext for users of the JSR-105 API.
Subscribe to:
Posts (Atom)